Skip to content

Commit d123d62

Browse files
committed
feature: findPostByPostId 의 날짜를 필수 형태로, findPostByPostUUID 를 고도화, 테스트 업데이트
1 parent da6eb20 commit d123d62

File tree

7 files changed

+85
-67
lines changed

7 files changed

+85
-67
lines changed

src/controllers/post.controller.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
} from '@/types';
1212

1313
export class PostController {
14-
constructor(private postService: PostService) {}
14+
constructor(private postService: PostService) { }
1515

1616
getAllPosts: RequestHandler = async (
1717
req: Request<object, object, object, GetAllPostsQuery>,
@@ -70,10 +70,9 @@ export class PostController {
7070
) => {
7171
try {
7272
const postId = Number(req.params.postId);
73-
const { start, end } = req.query;
7473

74+
const { start, end } = req.query;
7575
const post = await this.postService.getPostByPostId(postId, start, end);
76-
7776
const response = new PostResponseDto(true, '단건 post 조회에 성공하였습니다.', { post }, null);
7877

7978
res.status(200).json(response);

src/repositories/__test__/post.repo.integration.test.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { Pool } from 'pg';
33
import pg from 'pg';
44
import { PostRepository } from '../post.repository';
55
import logger from '@/configs/logger.config';
6+
import { getCurrentKSTDateString, getKSTDateStringWithOffset } from '@/utils/date.util';
67

78

89
dotenv.config();
@@ -407,7 +408,9 @@ describe('PostRepository 통합 테스트', () => {
407408
*/
408409
describe('findPostByPostId', () => {
409410
it('게시물 ID로 통계 데이터를 조회할 수 있어야 한다', async () => {
410-
const result = await repo.findPostByPostId(TEST_DATA.POST_ID);
411+
const sevenDayAgoKST = getKSTDateStringWithOffset(-24 * 60 * 7);
412+
const endKST = getCurrentKSTDateString();
413+
const result = await repo.findPostByPostId(TEST_DATA.POST_ID, sevenDayAgoKST, endKST);
411414

412415
expect(result).toBeDefined();
413416
expect(Array.isArray(result)).toBe(true);
@@ -437,7 +440,9 @@ describe('PostRepository 통합 테스트', () => {
437440
});
438441

439442
it('날짜 오름차순으로 정렬된 결과를 반환해야 한다', async () => {
440-
const result = await repo.findPostByPostId(TEST_DATA.POST_ID);
443+
const sevenDayAgoKST = getKSTDateStringWithOffset(-24 * 60 * 7);
444+
const endKST = getCurrentKSTDateString();
445+
const result = await repo.findPostByPostId(TEST_DATA.POST_ID, sevenDayAgoKST, endKST);
441446

442447
// 2개 이상의 결과가 있는 경우에만 정렬 검증
443448
if (result.length >= 2) {
@@ -459,16 +464,20 @@ describe('PostRepository 통합 테스트', () => {
459464
});
460465

461466
it('존재하지 않는 게시물 ID에 대해 빈 배열을 반환해야 한다', async () => {
467+
const sevenDayAgoKST = getKSTDateStringWithOffset(-24 * 60 * 7);
468+
const endKST = getCurrentKSTDateString();
462469
const nonExistentPostId = 9999999;
463-
const result = await repo.findPostByPostId(nonExistentPostId);
470+
const result = await repo.findPostByPostId(nonExistentPostId, sevenDayAgoKST, endKST);
464471

465472
expect(result).toBeDefined();
466473
expect(Array.isArray(result)).toBe(true);
467474
expect(result.length).toBe(0);
468475
});
469476

470477
it('날짜 형식이 올바르게 변환되어야 한다', async () => {
471-
const result = await repo.findPostByPostId(TEST_DATA.POST_ID);
478+
const sevenDayAgoKST = getKSTDateStringWithOffset(-24 * 60 * 7);
479+
const endKST = getCurrentKSTDateString();
480+
const result = await repo.findPostByPostId(TEST_DATA.POST_ID, sevenDayAgoKST, endKST);
472481

473482
if (result.length <= 0) {
474483
logger.info('존재하지 않는 게시물 ID에 대해 빈 배열을 테스트를 위한 충분한 데이터가 없습니다.');
@@ -490,7 +499,9 @@ describe('PostRepository 통합 테스트', () => {
490499
});
491500

492501
it('일일 조회수와 좋아요 수가 숫자 타입이어야 한다', async () => {
493-
const result = await repo.findPostByPostId(TEST_DATA.POST_ID);
502+
const sevenDayAgoKST = getKSTDateStringWithOffset(-24 * 60 * 7);
503+
const endKST = getCurrentKSTDateString();
504+
const result = await repo.findPostByPostId(TEST_DATA.POST_ID, sevenDayAgoKST, endKST);
494505

495506
if (result.length <= 0) {
496507
logger.info('일일 조회수와 좋아요 수가 숫자 타입인지 테스트를 위한 충분한 데이터가 없습니다.');

src/repositories/__test__/post.repo.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ describe('PostRepository', () => {
240240

241241
mockPool.query.mockResolvedValue(createMockQueryResult(mockStats));
242242

243-
const result = await repo.findPostByPostId(1);
243+
const result = await repo.findPostByPostId(1, '2025-05-01', '2025-05-08');
244244
expect(result).toEqual(mockStats);
245245
});
246246
});

src/repositories/post.repository.ts

Lines changed: 43 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -270,48 +270,56 @@ export class PostRepository {
270270
}
271271
}
272272

273-
async findPostByPostId(postId: number, start?: string, end?: string) {
274-
try {
275-
// 기본 쿼리 부분
276-
const baseQuery = `
277-
SELECT
278-
pds.date,
279-
pds.daily_view_count,
280-
pds.daily_like_count
281-
FROM posts_postdailystatistics pds
282-
WHERE pds.post_id = $1
283-
`;
284-
285-
// 날짜 필터링 조건 구성
286-
let dateFilterQuery = '';
287-
const queryParams: Array<number | string> = [postId];
288-
289-
if (start && end) {
290-
dateFilterQuery = `
291-
AND pds.date >= $2
292-
AND pds.date <= $3
293-
`;
294-
queryParams.push(start, end);
295-
}
296-
297-
// 정렬 조건 추가
298-
const orderByQuery = `ORDER BY pds.date ASC`;
299-
300-
// 최종 쿼리 조합
301-
const fullQuery = [baseQuery, dateFilterQuery, orderByQuery].join(' ');
273+
/**
274+
* 특정 게시물의 주어진 날짜 범위 내 일별 통계를 조회합니다.
275+
*
276+
* @param postId - 통계를 조회할 게시물의 ID.
277+
* @param start - 조회 범위의 시작 날짜(포함), 'YYYY-MM-DD' 형식.
278+
* @param end - 조회 범위의 종료 날짜(포함), 'YYYY-MM-DD' 형식.
279+
* @returns 주어진 날짜 범위 내 일별 통계 배열을 반환하는 Promise:
280+
* - `date`: 통계 날짜.
281+
* - `daily_view_count`: 해당 날짜의 조회수.
282+
* - `daily_like_count`: 해당 날짜의 좋아요 수.
283+
* @throws {DBError} 데이터베이스 조회 중 오류가 발생한 경우.
284+
*/
285+
async findPostByPostId(postId: number, start: string, end: string) {
286+
const query = `
287+
SELECT
288+
pds.date,
289+
pds.daily_view_count,
290+
pds.daily_like_count
291+
FROM posts_postdailystatistics pds
292+
WHERE pds.post_id = $1
293+
AND pds.date >= $2
294+
AND pds.date <= $3
295+
ORDER BY pds.date ASC
296+
`;
302297

303-
// 쿼리 실행
304-
const result = await this.pool.query(fullQuery, queryParams);
298+
try {
299+
const values: Array<number | string> = [postId, start, end];
300+
const result = await this.pool.query(query, values);
305301
return result.rows;
306302
} catch (error) {
307303
logger.error('Post Repo findPostByPostId error:', error);
308304
throw new DBError('단건 post 조회 중 문제가 발생했습니다.');
309305
}
310306
}
311307

308+
/**
309+
* 특정 게시물의 uuid 값 기반으로 날짜 범위 내 일별 통계를 조회합니다. 익스텐션에서 사용합니다.
310+
*
311+
* @param postUUUID - 통계를 조회할 게시물의 UUID.
312+
* @param start - 조회 범위의 시작 날짜(포함), 'YYYY-MM-DD' 형식.
313+
* @param end - 조회 범위의 종료 날짜(포함), 'YYYY-MM-DD' 형식.
314+
* @returns 주어진 날짜 범위 내 일별 통계 배열을 반환하는 Promise:
315+
* - `date`: 통계 날짜.
316+
* - `daily_view_count`: 해당 날짜의 조회수.
317+
* - `daily_like_count`: 해당 날짜의 좋아요 수.
318+
* @throws {DBError} 데이터베이스 조회 중 오류가 발생한 경우.
319+
*/
312320
async findPostByPostUUID(postUUUID: string, start: string, end: string) {
313-
try {
314-
const query = `
321+
// findPostByPostId 와 다르게 UUID 가 기준이라 join 필수
322+
const query = `
315323
SELECT
316324
pds.date,
317325
pds.daily_view_count,
@@ -323,10 +331,10 @@ export class PostRepository {
323331
AND pds.date >= $2
324332
AND pds.date <= $3
325333
ORDER BY pds.date ASC
326-
`;
334+
`;
327335

336+
try {
328337
const values = [postUUUID, start, end];
329-
330338
const result = await this.pool.query(query, values);
331339
return result.rows;
332340
} catch (error) {

src/services/__test__/post.service.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -398,8 +398,8 @@ describe('PostService', () => {
398398
// 7일 범위 설정 확인 (현재 날짜 2025-03-15 기준)
399399
expect(postRepo.findPostByPostUUID).toHaveBeenCalledWith(
400400
'uuid-1234',
401-
'2025-03-15', // 현재 날짜 (테스트에서 고정된 날짜)
402-
'2025-03-15' // 현재 날짜 (테스트에서 고정된 날짜)
401+
'2025-03-08 00:00:00+09', // 현재 날짜 (테스트에서 고정된 날짜)
402+
'2025-03-15 00:00:00+09' // 현재 날짜 (테스트에서 고정된 날짜)
403403
);
404404
});
405405

src/services/post.service.ts

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logger from '@/configs/logger.config';
22
import { PostRepository } from '@/repositories/post.repository';
33
import { RawPostType } from '@/types';
4+
import { getCurrentKSTDateString, getKSTDateStringWithOffset } from '@/utils/date.util';
45

56
export class PostService {
67
constructor(private postRepo: PostRepository) { }
@@ -62,35 +63,27 @@ export class PostService {
6263

6364
async getPostByPostId(postId: number, start?: string, end?: string) {
6465
// start, end 가 yyyy-mm-dd 만 넘어옴, 이를 kst 형태로 바꿔줘야 함
65-
const kstStart = `${start} 00:00:00+09`;
66-
const kstEnd = `${end} 00:00:00+09`;
66+
const startKST = `${start} 00:00:00+09`;
67+
const endKST = `${end} 00:00:00+09`;
6768

6869
try {
69-
const posts = await this.postRepo.findPostByPostId(postId, kstStart, kstEnd);
70-
70+
const posts = await this.postRepo.findPostByPostId(postId, startKST, endKST);
7171
const transformedPosts = this.transformPosts(posts);
72-
7372
return transformedPosts;
7473
} catch (error) {
7574
logger.error('PostService getPost error : ', error);
7675
throw error;
7776
}
7877
}
7978

80-
// !! 해당 함수 사용하지 않는 것으로 보임, 추후 정리 필요
8179
async getPostByPostUUID(postUUUID: string) {
82-
try {
83-
const seoulNow = new Date(new Date().getTime() + 9 * 60 * 60 * 1000);
84-
const sevenDaysAgo = new Date(seoulNow);
85-
86-
const start = sevenDaysAgo.toISOString().split('T')[0];
87-
const end = seoulNow.toISOString().split('T')[0];
88-
sevenDaysAgo.setDate(seoulNow.getDate() - 6);
89-
90-
const posts = await this.postRepo.findPostByPostUUID(postUUUID, start, end);
80+
// 날짜가 넘어오지 않기에 기본적으로 7일로 세팅
81+
const sevenDayAgoKST = getKSTDateStringWithOffset(-24 * 60 * 7);
82+
const endKST = getCurrentKSTDateString(); // now
9183

84+
try {
85+
const posts = await this.postRepo.findPostByPostUUID(postUUUID, sevenDayAgoKST, endKST);
9286
const transformedPosts = this.transformPosts(posts);
93-
9487
return transformedPosts;
9588
} catch (error) {
9689
logger.error('PostService getPostByPostUUID error : ', error);

src/types/dto/requests/getPostQuery.type.ts

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { IsString, Validate } from 'class-validator';
1+
import { IsNotEmpty, IsString, Validate } from 'class-validator';
22

33
export interface PostParam extends Record<string, string> {
44
postId: string;
@@ -20,29 +20,36 @@ export interface GetPostQuery {
2020
* type: string
2121
* format: date
2222
* description: 조회 시작 날짜
23-
* nullable: true
23+
* nullable: false
2424
* end:
2525
* type: string
2626
* format: date
2727
* description: 조회 종료 날짜
28-
* nullable: true
28+
* nullable: false
2929
*/
3030
export class GetPostQueryDto {
3131
@IsString()
32+
@IsNotEmpty()
3233
@Validate((value: string) => {
3334
const date = new Date(value);
3435
return !isNaN(date.getTime());
3536
}, {
3637
message: '유효한 날짜 형식이 아닙니다. (예: YYYY-MM-DD)'
3738
})
38-
start?: string;
39+
start: string;
3940

4041
@IsString()
42+
@IsNotEmpty()
4143
@Validate((value: string) => {
4244
const date = new Date(value);
4345
return !isNaN(date.getTime());
4446
}, {
4547
message: '유효한 날짜 형식이 아닙니다. (예: YYYY-MM-DD)'
4648
})
47-
end?: string;
49+
end: string;
50+
51+
constructor(start: string, end: string) {
52+
this.start = start;
53+
this.end = end;
54+
}
4855
}

0 commit comments

Comments
 (0)