BLOG-44 Post overall page #64
@ -1,3 +1,4 @@
|
||||
pub mod color_response_dto;
|
||||
pub mod label_response_dto;
|
||||
pub mod post_controller;
|
||||
pub mod post_info_query_dto;
|
||||
|
@ -0,0 +1,22 @@
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::domain::entity::color::Color;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ColorResponseDto {
|
||||
pub red: u8,
|
||||
pub green: u8,
|
||||
pub blue: u8,
|
||||
pub alpha: u8,
|
||||
}
|
||||
|
||||
impl From<Color> for ColorResponseDto {
|
||||
fn from(color: Color) -> Self {
|
||||
Self {
|
||||
red: color.red,
|
||||
green: color.green,
|
||||
blue: color.blue,
|
||||
alpha: color.alpha,
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,14 @@
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::domain::entity::label::Label;
|
||||
use crate::{
|
||||
adapter::delivery::color_response_dto::ColorResponseDto, domain::entity::label::Label,
|
||||
};
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct LabelResponseDto {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub color: String,
|
||||
pub color: ColorResponseDto,
|
||||
}
|
||||
|
||||
impl From<Label> for LabelResponseDto {
|
||||
@ -14,7 +16,7 @@ impl From<Label> for LabelResponseDto {
|
||||
Self {
|
||||
id: entity.id,
|
||||
name: entity.name,
|
||||
color: format!("#{:08X}", entity.color),
|
||||
color: ColorResponseDto::from(entity.color),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,2 +1,6 @@
|
||||
pub mod color_mapper;
|
||||
pub mod label_mapper;
|
||||
pub mod post_db_service;
|
||||
pub mod post_info_mapper;
|
||||
pub mod post_mapper;
|
||||
pub mod post_repository_impl;
|
||||
|
16
backend/feature/post/src/adapter/gateway/color_mapper.rs
Normal file
16
backend/feature/post/src/adapter/gateway/color_mapper.rs
Normal file
@ -0,0 +1,16 @@
|
||||
use crate::domain::entity::color::Color;
|
||||
|
||||
pub struct ColorMapper {
|
||||
pub value: u32,
|
||||
}
|
||||
|
||||
impl ColorMapper {
|
||||
pub fn to_entity(&self) -> Color {
|
||||
Color {
|
||||
red: (self.value >> 24) as u8,
|
||||
green: ((self.value >> 16) & 0xFF) as u8,
|
||||
blue: ((self.value >> 8) & 0xFF) as u8,
|
||||
alpha: (self.value & 0xFF) as u8,
|
||||
}
|
||||
}
|
||||
}
|
17
backend/feature/post/src/adapter/gateway/label_mapper.rs
Normal file
17
backend/feature/post/src/adapter/gateway/label_mapper.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use crate::{adapter::gateway::color_mapper::ColorMapper, domain::entity::label::Label};
|
||||
|
||||
pub struct LabelMapper {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub color: ColorMapper,
|
||||
}
|
||||
|
||||
impl LabelMapper {
|
||||
pub fn to_entity(&self) -> Label {
|
||||
Label {
|
||||
id: self.id,
|
||||
name: self.name.clone(),
|
||||
color: self.color.to_entity(),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::{
|
||||
adapter::gateway::{post_info_mapper::PostInfoMapper, post_mapper::PostMapper},
|
||||
application::error::post_error::PostError,
|
||||
domain::entity::{post::Post, post_info::PostInfo},
|
||||
};
|
||||
|
||||
#[async_trait]
|
||||
pub trait PostDbService: Send + Sync {
|
||||
async fn get_all_post_info(&self, is_published_only: bool) -> Result<Vec<PostInfo>, PostError>;
|
||||
async fn get_full_post(&self, id: i32) -> Result<Post, PostError>;
|
||||
async fn get_all_post_info(
|
||||
&self,
|
||||
is_published_only: bool,
|
||||
) -> Result<Vec<PostInfoMapper>, PostError>;
|
||||
async fn get_full_post(&self, id: i32) -> Result<PostMapper, PostError>;
|
||||
}
|
||||
|
27
backend/feature/post/src/adapter/gateway/post_info_mapper.rs
Normal file
27
backend/feature/post/src/adapter/gateway/post_info_mapper.rs
Normal file
@ -0,0 +1,27 @@
|
||||
use chrono::{DateTime, NaiveDateTime, Utc};
|
||||
|
||||
use crate::{adapter::gateway::label_mapper::LabelMapper, domain::entity::post_info::PostInfo};
|
||||
|
||||
pub struct PostInfoMapper {
|
||||
pub id: i32,
|
||||
pub title: String,
|
||||
pub description: String,
|
||||
pub preview_image_url: String,
|
||||
pub published_time: Option<NaiveDateTime>,
|
||||
pub labels: Vec<LabelMapper>,
|
||||
}
|
||||
|
||||
impl PostInfoMapper {
|
||||
pub fn to_entity(&self) -> PostInfo {
|
||||
PostInfo {
|
||||
id: self.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::<Utc>::from_naive_utc_and_offset(dt, Utc)),
|
||||
labels: self.labels.iter().map(LabelMapper::to_entity).collect(),
|
||||
}
|
||||
}
|
||||
}
|
17
backend/feature/post/src/adapter/gateway/post_mapper.rs
Normal file
17
backend/feature/post/src/adapter/gateway/post_mapper.rs
Normal file
@ -0,0 +1,17 @@
|
||||
use crate::{adapter::gateway::post_info_mapper::PostInfoMapper, domain::entity::post::Post};
|
||||
|
||||
pub struct PostMapper {
|
||||
pub id: i32,
|
||||
pub info: PostInfoMapper,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
impl PostMapper {
|
||||
pub fn to_entity(&self) -> Post {
|
||||
Post {
|
||||
id: self.id,
|
||||
info: self.info.to_entity(),
|
||||
content: self.content.clone(),
|
||||
}
|
||||
}
|
||||
}
|
@ -22,10 +22,21 @@ impl PostRepositoryImpl {
|
||||
#[async_trait]
|
||||
impl PostRepository for PostRepositoryImpl {
|
||||
async fn get_all_post_info(&self, is_published_only: bool) -> Result<Vec<PostInfo>, PostError> {
|
||||
self.post_db_service.get_all_post_info(is_published_only).await
|
||||
self.post_db_service
|
||||
.get_all_post_info(is_published_only)
|
||||
.await
|
||||
.map(|mappers| {
|
||||
mappers
|
||||
.into_iter()
|
||||
.map(|mapper| mapper.to_entity())
|
||||
.collect::<Vec<PostInfo>>()
|
||||
})
|
||||
}
|
||||
|
||||
async fn get_full_post(&self, id: i32) -> Result<Post, PostError> {
|
||||
self.post_db_service.get_full_post(id).await
|
||||
self.post_db_service
|
||||
.get_full_post(id)
|
||||
.await
|
||||
.map(|mapper| mapper.to_entity())
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod color;
|
||||
pub mod label;
|
||||
pub mod post_info;
|
||||
pub mod post;
|
||||
|
6
backend/feature/post/src/domain/entity/color.rs
Normal file
6
backend/feature/post/src/domain/entity/color.rs
Normal file
@ -0,0 +1,6 @@
|
||||
pub struct Color {
|
||||
pub red: u8,
|
||||
pub green: u8,
|
||||
pub blue: u8,
|
||||
pub alpha: u8,
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
use crate::domain::entity::color::Color;
|
||||
|
||||
pub struct Label {
|
||||
pub id: i32,
|
||||
pub name: String,
|
||||
pub color: u32,
|
||||
pub color: Color,
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use async_trait::async_trait;
|
||||
use chrono::{DateTime, Utc};
|
||||
use sqlx::{Pool, Postgres};
|
||||
|
||||
use crate::{
|
||||
adapter::gateway::post_db_service::PostDbService,
|
||||
adapter::gateway::{
|
||||
color_mapper::ColorMapper, label_mapper::LabelMapper, post_db_service::PostDbService,
|
||||
post_info_mapper::PostInfoMapper, post_mapper::PostMapper,
|
||||
},
|
||||
application::error::post_error::PostError,
|
||||
domain::entity::{label::Label, post::Post, post_info::PostInfo},
|
||||
};
|
||||
|
||||
use super::{
|
||||
@ -27,7 +28,10 @@ impl PostDbServiceImpl {
|
||||
|
||||
#[async_trait]
|
||||
impl PostDbService for PostDbServiceImpl {
|
||||
async fn get_all_post_info(&self, is_published_only: bool) -> Result<Vec<PostInfo>, PostError> {
|
||||
async fn get_all_post_info(
|
||||
&self,
|
||||
is_published_only: bool,
|
||||
) -> Result<Vec<PostInfoMapper>, PostError> {
|
||||
let mut query_builder = sqlx::QueryBuilder::new(
|
||||
r#"
|
||||
SELECT
|
||||
@ -62,37 +66,37 @@ impl PostDbService for PostDbServiceImpl {
|
||||
.await
|
||||
.map_err(|err| PostError::DatabaseError(err.to_string()))?;
|
||||
|
||||
let mut post_info_map = HashMap::<i32, PostInfo>::new();
|
||||
let mut post_info_mappers_map = HashMap::<i32, PostInfoMapper>::new();
|
||||
|
||||
for record in records {
|
||||
let post_info = post_info_map
|
||||
let post_info = post_info_mappers_map
|
||||
.entry(record.post_id)
|
||||
.or_insert_with(|| PostInfo {
|
||||
.or_insert_with(|| PostInfoMapper {
|
||||
id: record.post_id,
|
||||
title: record.title,
|
||||
description: record.description,
|
||||
preview_image_url: record.preview_image_url,
|
||||
labels: Vec::new(),
|
||||
published_time: record
|
||||
.published_time
|
||||
.map(|dt| DateTime::<Utc>::from_naive_utc_and_offset(dt, Utc)),
|
||||
published_time: record.published_time,
|
||||
});
|
||||
|
||||
if let (Some(label_id), Some(label_name), Some(label_color)) =
|
||||
(record.label_id, record.label_name, record.label_color)
|
||||
{
|
||||
post_info.labels.push(Label {
|
||||
post_info.labels.push(LabelMapper {
|
||||
id: label_id,
|
||||
name: label_name,
|
||||
color: label_color as u32,
|
||||
color: ColorMapper {
|
||||
value: label_color as u32,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Ok(post_info_map.into_values().collect())
|
||||
Ok(post_info_mappers_map.into_values().collect())
|
||||
}
|
||||
|
||||
async fn get_full_post(&self, id: i32) -> Result<Post, PostError> {
|
||||
async fn get_full_post(&self, id: i32) -> Result<PostMapper, PostError> {
|
||||
let mut query_builder = sqlx::QueryBuilder::new(
|
||||
r#"
|
||||
SELECT
|
||||
@ -129,20 +133,20 @@ impl PostDbService for PostDbServiceImpl {
|
||||
return Err(PostError::NotFound);
|
||||
}
|
||||
|
||||
let mut post_map = HashMap::<i32, Post>::new();
|
||||
let mut post_mappers_map = HashMap::<i32, PostMapper>::new();
|
||||
|
||||
for record in records {
|
||||
let post = post_map.entry(record.post_id).or_insert_with(|| Post {
|
||||
let post = post_mappers_map
|
||||
.entry(record.post_id)
|
||||
.or_insert_with(|| PostMapper {
|
||||
id: record.post_id,
|
||||
info: PostInfo {
|
||||
info: PostInfoMapper {
|
||||
id: record.post_id,
|
||||
title: record.title,
|
||||
description: record.description,
|
||||
preview_image_url: record.preview_image_url,
|
||||
labels: Vec::new(),
|
||||
published_time: record
|
||||
.published_time
|
||||
.map(|dt| DateTime::<Utc>::from_naive_utc_and_offset(dt, Utc)),
|
||||
published_time: record.published_time,
|
||||
},
|
||||
content: record.content,
|
||||
});
|
||||
@ -150,15 +154,17 @@ impl PostDbService for PostDbServiceImpl {
|
||||
if let (Some(label_id), Some(label_name), Some(label_color)) =
|
||||
(record.label_id, record.label_name, record.label_color)
|
||||
{
|
||||
post.info.labels.push(Label {
|
||||
post.info.labels.push(LabelMapper {
|
||||
id: label_id,
|
||||
name: label_name,
|
||||
color: label_color as u32,
|
||||
color: ColorMapper {
|
||||
value: label_color as u32,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let post = post_map.into_values().next();
|
||||
let post = post_mappers_map.into_values().next();
|
||||
|
||||
match post {
|
||||
Some(v) => Ok(v),
|
||||
|
Loading…
x
Reference in New Issue
Block a user