From 6efd941395dae040c32ca52b8ce706cb2ad58bbb Mon Sep 17 00:00:00 2001 From: SquidSpirit Date: Sun, 12 Oct 2025 13:36:12 +0800 Subject: [PATCH] feat: add semantic_id field to post-related data structures and database migrations --- .../delivery/create_post_request_dto.rs | 2 ++ .../delivery/post_info_response_dto.rs | 2 ++ .../delivery/update_post_request_dto.rs | 2 ++ .../adapter/gateway/post_info_db_mapper.rs | 8 ++++++- .../adapter/gateway/post_repository_impl.rs | 2 ++ .../post/src/domain/entity/post_info.rs | 1 + .../src/framework/db/post_db_service_impl.rs | 23 ++++++++++++------- .../db/post_info_with_label_record.rs | 1 + .../framework/db/post_with_label_record.rs | 1 + ...011200359_add_semantic_id_to_post.down.sql | 5 ++++ ...20251011200359_add_semantic_id_to_post.sql | 7 ++++++ 11 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 backend/migrations/20251011200359_add_semantic_id_to_post.down.sql create mode 100644 backend/migrations/20251011200359_add_semantic_id_to_post.sql diff --git a/backend/feature/post/src/adapter/delivery/create_post_request_dto.rs b/backend/feature/post/src/adapter/delivery/create_post_request_dto.rs index c242d0a..874c059 100644 --- a/backend/feature/post/src/adapter/delivery/create_post_request_dto.rs +++ b/backend/feature/post/src/adapter/delivery/create_post_request_dto.rs @@ -6,6 +6,7 @@ use crate::domain::entity::{post::Post, post_info::PostInfo}; #[derive(Deserialize, ToSchema, Clone)] pub struct CreatePostRequestDto { + pub semantic_id: String, pub title: String, pub description: String, pub content: String, @@ -24,6 +25,7 @@ impl CreatePostRequestDto { id: -1, info: PostInfo { id: -1, + semantic_id: self.semantic_id, title: self.title, description: self.description, preview_image_url: self.preview_image_url, diff --git a/backend/feature/post/src/adapter/delivery/post_info_response_dto.rs b/backend/feature/post/src/adapter/delivery/post_info_response_dto.rs index 1a5e94e..bb83498 100644 --- a/backend/feature/post/src/adapter/delivery/post_info_response_dto.rs +++ b/backend/feature/post/src/adapter/delivery/post_info_response_dto.rs @@ -8,6 +8,7 @@ use super::label_response_dto::LabelResponseDto; #[derive(Serialize, ToSchema)] pub struct PostInfoResponseDto { pub id: i32, + pub semantic_id: String, pub title: String, pub description: String, pub labels: Vec, @@ -23,6 +24,7 @@ impl From for PostInfoResponseDto { fn from(entity: PostInfo) -> Self { Self { id: entity.id, + semantic_id: entity.semantic_id, title: entity.title, description: entity.description, preview_image_url: entity.preview_image_url, diff --git a/backend/feature/post/src/adapter/delivery/update_post_request_dto.rs b/backend/feature/post/src/adapter/delivery/update_post_request_dto.rs index 29f96a7..5f93c5f 100644 --- a/backend/feature/post/src/adapter/delivery/update_post_request_dto.rs +++ b/backend/feature/post/src/adapter/delivery/update_post_request_dto.rs @@ -6,6 +6,7 @@ use crate::domain::entity::{post::Post, post_info::PostInfo}; #[derive(Deserialize, ToSchema, Clone)] pub struct UpdatePostRequestDto { + pub semantic_id: String, pub title: String, pub description: String, pub content: String, @@ -24,6 +25,7 @@ impl UpdatePostRequestDto { id, info: PostInfo { id, + semantic_id: self.semantic_id, title: self.title, description: self.description, preview_image_url: self.preview_image_url, diff --git a/backend/feature/post/src/adapter/gateway/post_info_db_mapper.rs b/backend/feature/post/src/adapter/gateway/post_info_db_mapper.rs index 9b3ee32..6663175 100644 --- a/backend/feature/post/src/adapter/gateway/post_info_db_mapper.rs +++ b/backend/feature/post/src/adapter/gateway/post_info_db_mapper.rs @@ -4,6 +4,7 @@ use crate::{adapter::gateway::label_db_mapper::LabelMapper, domain::entity::post pub struct PostInfoMapper { pub id: i32, + pub semantic_id: String, pub title: String, pub description: String, pub preview_image_url: String, @@ -15,13 +16,18 @@ impl PostInfoMapper { pub fn into_entity(self) -> PostInfo { PostInfo { id: self.id, + semantic_id: self.semantic_id, title: self.title.clone(), description: self.description.clone(), preview_image_url: self.preview_image_url.clone(), published_time: self .published_time .map(|dt| DateTime::::from_naive_utc_and_offset(dt, Utc)), - labels: self.labels.into_iter().map(LabelMapper::into_entity).collect(), + labels: self + .labels + .into_iter() + .map(LabelMapper::into_entity) + .collect(), } } } diff --git a/backend/feature/post/src/adapter/gateway/post_repository_impl.rs b/backend/feature/post/src/adapter/gateway/post_repository_impl.rs index 6fb0f97..5ffc33e 100644 --- a/backend/feature/post/src/adapter/gateway/post_repository_impl.rs +++ b/backend/feature/post/src/adapter/gateway/post_repository_impl.rs @@ -44,6 +44,7 @@ impl PostRepository for PostRepositoryImpl { async fn create_post(&self, post: Post, label_ids: &[i32]) -> Result { let info_mapper = PostInfoMapper { id: post.info.id, + semantic_id: post.info.semantic_id, title: post.info.title, description: post.info.description, preview_image_url: post.info.preview_image_url, @@ -65,6 +66,7 @@ impl PostRepository for PostRepositoryImpl { async fn update_post(&self, post: Post, label_ids: &[i32]) -> Result<(), PostError> { let info_mapper = PostInfoMapper { id: post.info.id, + semantic_id: post.info.semantic_id, title: post.info.title, description: post.info.description, preview_image_url: post.info.preview_image_url, diff --git a/backend/feature/post/src/domain/entity/post_info.rs b/backend/feature/post/src/domain/entity/post_info.rs index ee5f7f9..bac3c34 100644 --- a/backend/feature/post/src/domain/entity/post_info.rs +++ b/backend/feature/post/src/domain/entity/post_info.rs @@ -4,6 +4,7 @@ use super::label::Label; pub struct PostInfo { pub id: i32, + pub semantic_id: String, pub title: String, pub description: String, pub preview_image_url: String, diff --git a/backend/feature/post/src/framework/db/post_db_service_impl.rs b/backend/feature/post/src/framework/db/post_db_service_impl.rs index 94d2de8..b2e3071 100644 --- a/backend/feature/post/src/framework/db/post_db_service_impl.rs +++ b/backend/feature/post/src/framework/db/post_db_service_impl.rs @@ -37,6 +37,7 @@ impl PostDbService for PostDbServiceImpl { r#" SELECT p.id AS post_id, + p.semantic_id, p.title, p.description, p.preview_image_url, @@ -74,6 +75,7 @@ impl PostDbService for PostDbServiceImpl { .entry(record.post_id) .or_insert_with(|| PostInfoMapper { id: record.post_id, + semantic_id: record.semantic_id.clone(), title: record.title.clone(), description: record.description.clone(), preview_image_url: record.preview_image_url.clone(), @@ -111,6 +113,7 @@ impl PostDbService for PostDbServiceImpl { r#" SELECT p.id AS post_id, + p.semantic_id, p.title, p.description, p.preview_image_url, @@ -151,6 +154,7 @@ impl PostDbService for PostDbServiceImpl { .or_insert_with(|| PostMapper { id: record.post_id, info: PostInfoMapper { + semantic_id: record.semantic_id.clone(), id: record.post_id, title: record.title.clone(), description: record.description.clone(), @@ -194,10 +198,11 @@ impl PostDbService for PostDbServiceImpl { let post_id = sqlx::query_scalar!( r#" INSERT INTO post ( - title, description, preview_image_url, content, published_time - ) VALUES ($1, $2, $3, $4, $5) + semantic_id, title, description, preview_image_url, content, published_time + ) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id "#, + post.info.semantic_id, post.info.title, post.info.description, post.info.preview_image_url, @@ -243,13 +248,15 @@ impl PostDbService for PostDbServiceImpl { r#" UPDATE post SET - title = $1, - description = $2, - preview_image_url = $3, - content = $4, - published_time = $5 - WHERE id = $6 + semantic_id = $1, + title = $2, + description = $3, + preview_image_url = $4, + content = $5, + published_time = $6 + WHERE id = $7 "#, + post.info.semantic_id, post.info.title, post.info.description, post.info.preview_image_url, diff --git a/backend/feature/post/src/framework/db/post_info_with_label_record.rs b/backend/feature/post/src/framework/db/post_info_with_label_record.rs index 2dc6a61..1d6bc9e 100644 --- a/backend/feature/post/src/framework/db/post_info_with_label_record.rs +++ b/backend/feature/post/src/framework/db/post_info_with_label_record.rs @@ -3,6 +3,7 @@ use chrono::NaiveDateTime; #[derive(sqlx::FromRow)] pub struct PostInfoWithLabelRecord { pub post_id: i32, + pub semantic_id: String, pub title: String, pub description: String, pub preview_image_url: String, diff --git a/backend/feature/post/src/framework/db/post_with_label_record.rs b/backend/feature/post/src/framework/db/post_with_label_record.rs index 20fcabe..2d0a2a0 100644 --- a/backend/feature/post/src/framework/db/post_with_label_record.rs +++ b/backend/feature/post/src/framework/db/post_with_label_record.rs @@ -3,6 +3,7 @@ use chrono::NaiveDateTime; #[derive(sqlx::FromRow)] pub struct PostWithLabelRecord { pub post_id: i32, + pub semantic_id: String, pub title: String, pub description: String, pub preview_image_url: String, diff --git a/backend/migrations/20251011200359_add_semantic_id_to_post.down.sql b/backend/migrations/20251011200359_add_semantic_id_to_post.down.sql new file mode 100644 index 0000000..5401e46 --- /dev/null +++ b/backend/migrations/20251011200359_add_semantic_id_to_post.down.sql @@ -0,0 +1,5 @@ +-- Drop the unique index on semantic_id +DROP INDEX IF EXISTS idx_post_semantic_id; + +-- Remove the semantic_id column from post table +ALTER TABLE post DROP COLUMN IF EXISTS "semantic_id"; diff --git a/backend/migrations/20251011200359_add_semantic_id_to_post.sql b/backend/migrations/20251011200359_add_semantic_id_to_post.sql new file mode 100644 index 0000000..63d0294 --- /dev/null +++ b/backend/migrations/20251011200359_add_semantic_id_to_post.sql @@ -0,0 +1,7 @@ +ALTER TABLE post ADD COLUMN "semantic_id" VARCHAR(100) NOT NULL DEFAULT ''; + +-- Update existing records to use their id as semantic_id +UPDATE post SET semantic_id = id::VARCHAR WHERE semantic_id = ''; + +-- Create unique index on semantic_id +CREATE UNIQUE INDEX idx_post_semantic_id ON post (semantic_id);