feat: implement retrieval of posts by semantic ID and update related use cases
This commit is contained in:
parent
6efd941395
commit
43582af2a5
@ -15,8 +15,9 @@ use crate::{
|
|||||||
create_label_use_case::CreateLabelUseCase, create_post_use_case::CreatePostUseCase,
|
create_label_use_case::CreateLabelUseCase, create_post_use_case::CreatePostUseCase,
|
||||||
get_all_labels_use_case::GetAllLabelsUseCase,
|
get_all_labels_use_case::GetAllLabelsUseCase,
|
||||||
get_all_post_info_use_case::GetAllPostInfoUseCase,
|
get_all_post_info_use_case::GetAllPostInfoUseCase,
|
||||||
get_full_post_use_case::GetFullPostUseCase, update_label_use_case::UpdateLabelUseCase,
|
get_post_by_id_use_case::GetPostByIdUseCase,
|
||||||
update_post_use_case::UpdatePostUseCase,
|
get_post_by_sementic_id_use_case::GetPostBySemanticIdUseCase,
|
||||||
|
update_label_use_case::UpdateLabelUseCase, update_post_use_case::UpdatePostUseCase,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@ -34,9 +35,9 @@ pub trait PostController: Send + Sync {
|
|||||||
user_id: Option<i32>,
|
user_id: Option<i32>,
|
||||||
) -> Result<Vec<PostInfoResponseDto>, PostError>;
|
) -> Result<Vec<PostInfoResponseDto>, PostError>;
|
||||||
|
|
||||||
async fn get_post_by_id(
|
async fn get_post_by_id_or_semantic_id(
|
||||||
&self,
|
&self,
|
||||||
id: i32,
|
id_or_semantic_id: &str,
|
||||||
user_id: Option<i32>,
|
user_id: Option<i32>,
|
||||||
) -> Result<PostResponseDto, PostError>;
|
) -> Result<PostResponseDto, PostError>;
|
||||||
|
|
||||||
@ -69,7 +70,8 @@ pub trait PostController: Send + Sync {
|
|||||||
|
|
||||||
pub struct PostControllerImpl {
|
pub struct PostControllerImpl {
|
||||||
get_all_post_info_use_case: Arc<dyn GetAllPostInfoUseCase>,
|
get_all_post_info_use_case: Arc<dyn GetAllPostInfoUseCase>,
|
||||||
get_full_post_use_case: Arc<dyn GetFullPostUseCase>,
|
get_post_by_id_use_case: Arc<dyn GetPostByIdUseCase>,
|
||||||
|
get_post_by_semantic_id_use_case: Arc<dyn GetPostBySemanticIdUseCase>,
|
||||||
create_post_use_case: Arc<dyn CreatePostUseCase>,
|
create_post_use_case: Arc<dyn CreatePostUseCase>,
|
||||||
update_post_use_case: Arc<dyn UpdatePostUseCase>,
|
update_post_use_case: Arc<dyn UpdatePostUseCase>,
|
||||||
create_label_use_case: Arc<dyn CreateLabelUseCase>,
|
create_label_use_case: Arc<dyn CreateLabelUseCase>,
|
||||||
@ -80,7 +82,8 @@ pub struct PostControllerImpl {
|
|||||||
impl PostControllerImpl {
|
impl PostControllerImpl {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
get_all_post_info_use_case: Arc<dyn GetAllPostInfoUseCase>,
|
get_all_post_info_use_case: Arc<dyn GetAllPostInfoUseCase>,
|
||||||
get_full_post_use_case: Arc<dyn GetFullPostUseCase>,
|
get_post_by_id_use_case: Arc<dyn GetPostByIdUseCase>,
|
||||||
|
get_post_by_semantic_id_use_case: Arc<dyn GetPostBySemanticIdUseCase>,
|
||||||
create_post_use_case: Arc<dyn CreatePostUseCase>,
|
create_post_use_case: Arc<dyn CreatePostUseCase>,
|
||||||
update_post_use_case: Arc<dyn UpdatePostUseCase>,
|
update_post_use_case: Arc<dyn UpdatePostUseCase>,
|
||||||
create_label_use_case: Arc<dyn CreateLabelUseCase>,
|
create_label_use_case: Arc<dyn CreateLabelUseCase>,
|
||||||
@ -89,7 +92,8 @@ impl PostControllerImpl {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
get_all_post_info_use_case,
|
get_all_post_info_use_case,
|
||||||
get_full_post_use_case,
|
get_post_by_id_use_case,
|
||||||
|
get_post_by_semantic_id_use_case,
|
||||||
create_post_use_case,
|
create_post_use_case,
|
||||||
update_post_use_case,
|
update_post_use_case,
|
||||||
create_label_use_case,
|
create_label_use_case,
|
||||||
@ -97,6 +101,29 @@ impl PostControllerImpl {
|
|||||||
get_all_labels_use_case,
|
get_all_labels_use_case,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_post_by_id(
|
||||||
|
&self,
|
||||||
|
id: i32,
|
||||||
|
user_id: Option<i32>,
|
||||||
|
) -> Result<PostResponseDto, PostError> {
|
||||||
|
let result = self.get_post_by_id_use_case.execute(id, user_id).await;
|
||||||
|
|
||||||
|
result.map(PostResponseDto::from)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_post_by_semantic_id(
|
||||||
|
&self,
|
||||||
|
semantic_id: &str,
|
||||||
|
user_id: Option<i32>,
|
||||||
|
) -> Result<PostResponseDto, PostError> {
|
||||||
|
let result = self
|
||||||
|
.get_post_by_semantic_id_use_case
|
||||||
|
.execute(semantic_id, user_id)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
result.map(PostResponseDto::from)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
@ -121,14 +148,17 @@ impl PostController for PostControllerImpl {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_post_by_id(
|
async fn get_post_by_id_or_semantic_id(
|
||||||
&self,
|
&self,
|
||||||
id: i32,
|
id_or_semantic_id: &str,
|
||||||
user_id: Option<i32>,
|
user_id: Option<i32>,
|
||||||
) -> Result<PostResponseDto, PostError> {
|
) -> Result<PostResponseDto, PostError> {
|
||||||
let result = self.get_full_post_use_case.execute(id, user_id).await;
|
if let Ok(id) = id_or_semantic_id.parse::<i32>() {
|
||||||
|
self.get_post_by_id(id, user_id).await
|
||||||
result.map(PostResponseDto::from)
|
} else {
|
||||||
|
let semantic_id = id_or_semantic_id;
|
||||||
|
self.get_post_by_semantic_id(semantic_id, user_id).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_label(
|
async fn create_label(
|
||||||
|
@ -14,4 +14,5 @@ pub trait PostDbService: Send + Sync {
|
|||||||
async fn get_post_by_id(&self, id: i32) -> Result<PostMapper, PostError>;
|
async fn get_post_by_id(&self, id: i32) -> Result<PostMapper, PostError>;
|
||||||
async fn create_post(&self, post: PostMapper, label_ids: &[i32]) -> Result<i32, PostError>;
|
async fn create_post(&self, post: PostMapper, label_ids: &[i32]) -> Result<i32, PostError>;
|
||||||
async fn update_post(&self, post: PostMapper, label_ids: &[i32]) -> Result<(), PostError>;
|
async fn update_post(&self, post: PostMapper, label_ids: &[i32]) -> Result<(), PostError>;
|
||||||
|
async fn get_id_by_semantic_id(&self, semantic_id: &str) -> Result<i32, PostError>;
|
||||||
}
|
}
|
||||||
|
@ -84,4 +84,8 @@ impl PostRepository for PostRepositoryImpl {
|
|||||||
.update_post(post_mapper, label_ids)
|
.update_post(post_mapper, label_ids)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_id_by_semantic_id(&self, semantic_id: &str) -> Result<i32, PostError> {
|
||||||
|
self.post_db_service.get_id_by_semantic_id(semantic_id).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,4 +11,5 @@ pub trait PostRepository: Send + Sync {
|
|||||||
async fn get_post_by_id(&self, id: i32) -> Result<Post, PostError>;
|
async fn get_post_by_id(&self, id: i32) -> Result<Post, PostError>;
|
||||||
async fn create_post(&self, post: Post, label_ids: &[i32]) -> Result<i32, PostError>;
|
async fn create_post(&self, post: Post, label_ids: &[i32]) -> Result<i32, PostError>;
|
||||||
async fn update_post(&self, post: Post, label_ids: &[i32]) -> Result<(), PostError>;
|
async fn update_post(&self, post: Post, label_ids: &[i32]) -> Result<(), PostError>;
|
||||||
|
async fn get_id_by_semantic_id(&self, semantic_id: &str) -> Result<i32, PostError>;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ pub mod create_label_use_case;
|
|||||||
pub mod create_post_use_case;
|
pub mod create_post_use_case;
|
||||||
pub mod get_all_labels_use_case;
|
pub mod get_all_labels_use_case;
|
||||||
pub mod get_all_post_info_use_case;
|
pub mod get_all_post_info_use_case;
|
||||||
pub mod get_full_post_use_case;
|
pub mod get_post_by_id_use_case;
|
||||||
|
pub mod get_post_by_sementic_id_use_case;
|
||||||
pub mod update_label_use_case;
|
pub mod update_label_use_case;
|
||||||
pub mod update_post_use_case;
|
pub mod update_post_use_case;
|
||||||
|
@ -8,7 +8,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
pub trait GetFullPostUseCase: Send + Sync {
|
pub trait GetPostByIdUseCase: Send + Sync {
|
||||||
async fn execute(&self, id: i32, user_id: Option<i32>) -> Result<Post, PostError>;
|
async fn execute(&self, id: i32, user_id: Option<i32>) -> Result<Post, PostError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ impl GetFullPostUseCaseImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl GetFullPostUseCase for GetFullPostUseCaseImpl {
|
impl GetPostByIdUseCase for GetFullPostUseCaseImpl {
|
||||||
async fn execute(&self, id: i32, user_id: Option<i32>) -> Result<Post, PostError> {
|
async fn execute(&self, id: i32, user_id: Option<i32>) -> Result<Post, PostError> {
|
||||||
let post = self.post_repository.get_post_by_id(id).await?;
|
let post = self.post_repository.get_post_by_id(id).await?;
|
||||||
|
|
@ -0,0 +1,45 @@
|
|||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use async_trait::async_trait;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
application::{
|
||||||
|
error::post_error::PostError, gateway::post_repository::PostRepository,
|
||||||
|
use_case::get_post_by_id_use_case::GetPostByIdUseCase,
|
||||||
|
},
|
||||||
|
domain::entity::post::Post,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
pub trait GetPostBySemanticIdUseCase: Send + Sync {
|
||||||
|
async fn execute(&self, semantic_id: &str, user_id: Option<i32>) -> Result<Post, PostError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct GetPostIdBySemanticIdUseCaseImpl {
|
||||||
|
post_repository: Arc<dyn PostRepository>,
|
||||||
|
get_post_by_id_use_case: Arc<dyn GetPostByIdUseCase>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GetPostIdBySemanticIdUseCaseImpl {
|
||||||
|
pub fn new(
|
||||||
|
post_repository: Arc<dyn PostRepository>,
|
||||||
|
get_post_by_id_use_case: Arc<dyn GetPostByIdUseCase>,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
post_repository,
|
||||||
|
get_post_by_id_use_case,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait]
|
||||||
|
impl GetPostBySemanticIdUseCase for GetPostIdBySemanticIdUseCaseImpl {
|
||||||
|
async fn execute(&self, semantic_id: &str, user_id: Option<i32>) -> Result<Post, PostError> {
|
||||||
|
let id = self
|
||||||
|
.post_repository
|
||||||
|
.get_id_by_semantic_id(semantic_id)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
self.get_post_by_id_use_case.execute(id, user_id).await
|
||||||
|
}
|
||||||
|
}
|
@ -307,4 +307,23 @@ impl PostDbService for PostDbServiceImpl {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_id_by_semantic_id(&self, semantic_id: &str) -> Result<i32, PostError> {
|
||||||
|
let id = sqlx::query_scalar!(
|
||||||
|
r#"
|
||||||
|
SELECT id
|
||||||
|
FROM post
|
||||||
|
WHERE semantic_id = $1 AND deleted_time IS NULL
|
||||||
|
"#,
|
||||||
|
semantic_id,
|
||||||
|
)
|
||||||
|
.fetch_optional(&self.db_pool)
|
||||||
|
.await
|
||||||
|
.map_err(|e| PostError::Unexpected(DatabaseError(e).into()))?;
|
||||||
|
|
||||||
|
match id {
|
||||||
|
Some(id) => Ok(id),
|
||||||
|
None => Err(PostError::NotFound),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,8 +11,8 @@ use crate::{
|
|||||||
get,
|
get,
|
||||||
path = "/post/{id}",
|
path = "/post/{id}",
|
||||||
tag = "post",
|
tag = "post",
|
||||||
summary = "Get post by ID",
|
summary = "Get post by ID or semantic ID",
|
||||||
description = "Only authenticated users can access unpublished posts.",
|
description = "Only authenticated users can access unpublished posts. Accepts either numeric ID or semantic ID.",
|
||||||
responses (
|
responses (
|
||||||
(status = 200, body = PostResponseDto),
|
(status = 200, body = PostResponseDto),
|
||||||
(status = 404, description = "Post not found")
|
(status = 404, description = "Post not found")
|
||||||
@ -20,12 +20,12 @@ use crate::{
|
|||||||
)]
|
)]
|
||||||
pub async fn get_post_by_id_handler(
|
pub async fn get_post_by_id_handler(
|
||||||
post_controller: web::Data<dyn PostController>,
|
post_controller: web::Data<dyn PostController>,
|
||||||
path: web::Path<i32>,
|
path: web::Path<String>,
|
||||||
user_id: Option<UserId>,
|
user_id: Option<UserId>,
|
||||||
) -> impl Responder {
|
) -> impl Responder {
|
||||||
let id = path.into_inner();
|
let id_or_semantic_id = path.into_inner();
|
||||||
let result = post_controller
|
let result = post_controller
|
||||||
.get_post_by_id(id, user_id.map(|id| id.get()))
|
.get_post_by_id_or_semantic_id(&id_or_semantic_id, user_id.map(|id| id.get()))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
|
@ -36,13 +36,12 @@ use post::{
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
application::use_case::{
|
application::use_case::{
|
||||||
create_label_use_case::CreateLabelUseCaseImpl,
|
create_label_use_case::CreateLabelUseCaseImpl, create_post_use_case::CreatePostUseCaseImpl,
|
||||||
create_post_use_case::CreatePostUseCaseImpl,
|
|
||||||
get_all_labels_use_case::GetAllLabelsUseCaseImpl,
|
get_all_labels_use_case::GetAllLabelsUseCaseImpl,
|
||||||
get_all_post_info_use_case::GetAllPostInfoUseCaseImpl,
|
get_all_post_info_use_case::GetAllPostInfoUseCaseImpl,
|
||||||
get_full_post_use_case::GetFullPostUseCaseImpl,
|
get_post_by_id_use_case::GetFullPostUseCaseImpl,
|
||||||
update_label_use_case::UpdateLabelUseCaseImpl,
|
get_post_by_sementic_id_use_case::GetPostIdBySemanticIdUseCaseImpl,
|
||||||
update_post_use_case::UpdatePostUseCaseImpl,
|
update_label_use_case::UpdateLabelUseCaseImpl, update_post_use_case::UpdatePostUseCaseImpl,
|
||||||
},
|
},
|
||||||
framework::db::{
|
framework::db::{
|
||||||
label_db_service_impl::LabelDbServiceImpl, post_db_service_impl::PostDbServiceImpl,
|
label_db_service_impl::LabelDbServiceImpl, post_db_service_impl::PostDbServiceImpl,
|
||||||
@ -97,7 +96,12 @@ impl Container {
|
|||||||
|
|
||||||
let get_all_post_info_use_case =
|
let get_all_post_info_use_case =
|
||||||
Arc::new(GetAllPostInfoUseCaseImpl::new(post_repository.clone()));
|
Arc::new(GetAllPostInfoUseCaseImpl::new(post_repository.clone()));
|
||||||
let get_full_post_use_case = Arc::new(GetFullPostUseCaseImpl::new(post_repository.clone()));
|
let get_post_by_id_use_case =
|
||||||
|
Arc::new(GetFullPostUseCaseImpl::new(post_repository.clone()));
|
||||||
|
let get_post_by_semantic_id_use_case = Arc::new(GetPostIdBySemanticIdUseCaseImpl::new(
|
||||||
|
post_repository.clone(),
|
||||||
|
get_post_by_id_use_case.clone(),
|
||||||
|
));
|
||||||
let create_post_use_case = Arc::new(CreatePostUseCaseImpl::new(post_repository.clone()));
|
let create_post_use_case = Arc::new(CreatePostUseCaseImpl::new(post_repository.clone()));
|
||||||
let update_post_use_case = Arc::new(UpdatePostUseCaseImpl::new(post_repository.clone()));
|
let update_post_use_case = Arc::new(UpdatePostUseCaseImpl::new(post_repository.clone()));
|
||||||
let create_label_use_case = Arc::new(CreateLabelUseCaseImpl::new(label_repository.clone()));
|
let create_label_use_case = Arc::new(CreateLabelUseCaseImpl::new(label_repository.clone()));
|
||||||
@ -107,7 +111,8 @@ impl Container {
|
|||||||
|
|
||||||
let post_controller = Arc::new(PostControllerImpl::new(
|
let post_controller = Arc::new(PostControllerImpl::new(
|
||||||
get_all_post_info_use_case,
|
get_all_post_info_use_case,
|
||||||
get_full_post_use_case,
|
get_post_by_id_use_case,
|
||||||
|
get_post_by_semantic_id_use_case,
|
||||||
create_post_use_case,
|
create_post_use_case,
|
||||||
update_post_use_case,
|
update_post_use_case,
|
||||||
create_label_use_case,
|
create_label_use_case,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user