Skip to content

Commit a06bdc5

Browse files
authored
Merge pull request #96 from umc-commit/refactor/get-bookmarks
[REFACTOR] 북마크 조회 페이지네이션 방식 변경
2 parents b7f5634 + c676ca0 commit a06bdc5

5 files changed

Lines changed: 55 additions & 86 deletions

File tree

src/bookmark/controller/bookmark.controller.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,8 @@ export const getBookmarks = async (req, res, next) => {
7676
const userId = BigInt(req.user.userId);
7777
const dto = new GetBookmarksDto({
7878
sort: req.query.sort,
79+
page: req.query.page ? parseInt(req.query.page) : undefined,
7980
limit: req.query.limit ? parseInt(req.query.limit) : undefined,
80-
cursor: req.query.cursor,
8181
excludeFullSlots: req.query.excludeFullSlots === 'true'
8282
});
8383

src/bookmark/dto/bookmark.dto.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ export class DeleteSelectedBookmarksDto {
2222

2323
// 사용자 북마크 조회 dto
2424
export class GetBookmarksDto {
25-
constructor({ sort, limit, cursor, excludeFullSlots }) {
25+
constructor({ sort, page, limit, excludeFullSlots }) {
2626
this.sort = sort || 'latest';
27+
this.page = page || 1;
2728
this.limit = limit || 12;
28-
this.cursor = cursor || null;
2929
this.excludeFullSlots = excludeFullSlots || false;
3030
}
3131
}

src/bookmark/repository/bookmark.repository.js

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -70,60 +70,36 @@ export const BookmarkRepository = {
7070
},
7171

7272
/**
73-
* 사용자의 북마크 목록 조회 (커서 기반 페이징)
73+
* 사용자의 북마크 목록 조회
7474
*/
7575
async findBookmarksByUserId(userId, dto) {
76-
const { sort, limit, cursor, excludeFullSlots = false } = dto;
76+
const { sort, page, limit, excludeFullSlots = false } = dto;
7777

7878
const baseCondition = {
79-
userId: BigInt(userId)
79+
userId: BigInt(userId)
8080
};
8181

8282
let whereCondition = { ...baseCondition };
8383
let orderBy = [];
8484

85-
if (cursor) {
86-
const decodedCursor = JSON.parse(Buffer.from(cursor, 'base64').toString());
87-
switch (sort) {
88-
case 'latest': // 최신순 정렬
89-
whereCondition.createdAt = { lt: new Date(decodedCursor.created_at) };
90-
orderBy = [{ createdAt: 'desc' }, { id: 'desc' }];
91-
break;
92-
case 'price_low': // 저가순 정렬
93-
whereCondition.OR = [
94-
{ commission: { minPrice: { gt: decodedCursor.min_price } } },
95-
{
96-
commission: { minPrice: decodedCursor.min_price },
97-
createdAt: { lt: new Date(decodedCursor.created_at) }
98-
}
99-
];
100-
orderBy = [{ commission: { minPrice: 'asc' } }, { createdAt: 'desc' }];
101-
break;
102-
case 'price_high': // 고가순 정렬
103-
whereCondition.OR = [
104-
{ commission: { minPrice: { lt: decodedCursor.min_price } } },
105-
{
106-
commission: { minPrice: decodedCursor.min_price },
107-
createdAt: { lt: new Date(decodedCursor.created_at) }
108-
}
109-
];
110-
orderBy = [{ commission: { minPrice: 'desc' } }, { createdAt: 'desc' }];
111-
break;
112-
}
113-
} else {
114-
switch (sort) {
115-
case 'latest':
116-
orderBy = [{ createdAt: 'desc' }, { id: 'desc' }];
117-
break;
118-
case 'price_low':
119-
orderBy = [{ commission: { minPrice: 'asc' } }, { createdAt: 'desc' }];
120-
break;
121-
case 'price_high':
122-
orderBy = [{ commission: { minPrice: 'desc' } }, { createdAt: 'desc' }];
123-
break;
124-
}
85+
// 정렬 조건 설정
86+
switch (sort) {
87+
case 'latest':
88+
orderBy = [{ createdAt: 'desc' }, { id: 'desc' }];
89+
break;
90+
case 'price_low':
91+
orderBy = [{ commission: { minPrice: 'asc' } }, { createdAt: 'desc' }];
92+
break;
93+
case 'price_high':
94+
orderBy = [{ commission: { minPrice: 'desc' } }, { createdAt: 'desc' }];
95+
break;
96+
default:
97+
orderBy = [{ createdAt: 'desc' }, { id: 'desc' }];
12598
}
12699

100+
// 페이지네이션 계산
101+
const skip = (page - 1) * limit;
102+
127103
return await prisma.bookmark.findMany({
128104
where: whereCondition,
129105
include: {
@@ -165,7 +141,8 @@ export const BookmarkRepository = {
165141
}
166142
},
167143
orderBy,
168-
take: excludeFullSlots ? 100 : limit + 1, // hasNext 확인용
144+
skip,
145+
take: limit
169146
});
170147
},
171148

src/bookmark/service/bookmark.service.js

Lines changed: 12 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -94,17 +94,17 @@ export const BookmarkService = {
9494
};
9595
},
9696

97-
// 북마크 목록 조회
97+
// 북마크 목록 조회
9898
async getBookmarks(userId, dto) {
99-
const { sort, limit, cursor, excludeFullSlots = false } = dto;
99+
const { sort, page, limit, excludeFullSlots = false } = dto;
100100

101101
const bookmarks = await BookmarkRepository.findBookmarksByUserId(userId, dto);
102102

103103
const totalCount = excludeFullSlots
104104
? await BookmarkRepository.countAvailableBookmarksByUserId(userId)
105105
: await BookmarkRepository.countBookmarksByUserId(userId);
106106

107-
// 응답 데이터 가공 (모든 데이터 포맷팅)
107+
// 응답 데이터 가공
108108
const formattedItems = await Promise.all(
109109
bookmarks.map(async (bookmark) => {
110110
// 썸네일 이미지 조회
@@ -134,33 +134,17 @@ export const BookmarkService = {
134134
? formattedItems.filter(item => item.remainingSlots > 0)
135135
: formattedItems;
136136

137-
const hasNext = filteredItems.length > limit;
138-
const finalItems = hasNext ? filteredItems.slice(0, -1) : filteredItems;
139-
140-
// nextCursor 생성
141-
let nextCursor = null;
142-
if (hasNext && finalItems.length > 0) {
143-
const lastFormattedItem = finalItems[finalItems.length - 1];
144-
const originalBookmark = bookmarks.find(b => Number(b.commission.id) === lastFormattedItem.id);
145-
146-
const cursorData = {
147-
id: lastFormattedItem.id,
148-
created_at: originalBookmark.createdAt.toISOString()
149-
};
150-
151-
if (sort === 'price_low' || sort === 'price_high') {
152-
cursorData.min_price = lastFormattedItem.minPrice;
153-
}
154-
155-
nextCursor = Buffer.from(JSON.stringify(cursorData)).toString('base64');
156-
}
157-
137+
// 페이지네이션 계산
138+
const totalPages = Math.ceil(totalCount / limit);
158139

159140
return {
160-
totalCount,
161-
hasNext,
162-
nextCursor,
163-
items: finalItems
141+
items: filteredItems,
142+
pagination: {
143+
page,
144+
limit,
145+
totalCount,
146+
totalPages
147+
}
164148
};
165149
},
166150
};

src/common/swagger/bookmark.json

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@
219219
"get": {
220220
"tags": ["Bookmark"],
221221
"summary": "북마크 목록 조회",
222-
"description": "사용자의 북마크한 커미션 목록을 조회합니다. 정렬 및 무한스크롤 페이징을 지원합니다.",
222+
"description": "사용자의 북마크한 커미션 목록을 조회합니다.",
223223
"security": [
224224
{
225225
"bearerAuth": []
@@ -238,25 +238,27 @@
238238
"description": "정렬 방식"
239239
},
240240
{
241-
"name": "limit",
241+
"name": "page",
242242
"in": "query",
243243
"required": false,
244244
"schema": {
245245
"type": "integer",
246246
"minimum": 1,
247-
"maximum": 50,
248-
"default": 12
247+
"default": 1
249248
},
250-
"description": "한 번에 가져올 개수"
249+
"description": "페이지 번호"
251250
},
252251
{
253-
"name": "cursor",
252+
"name": "limit",
254253
"in": "query",
255254
"required": false,
256255
"schema": {
257-
"type": "string"
256+
"type": "integer",
257+
"minimum": 1,
258+
"maximum": 50,
259+
"default": 12
258260
},
259-
"description": "다음 페이지 조회용 커서"
261+
"description": "한 번에 가져올 개수"
260262
},
261263
{
262264
"name": "excludeFullSlots",
@@ -282,9 +284,6 @@
282284
"success": {
283285
"type": "object",
284286
"properties": {
285-
"totalCount": { "type": "integer", "example": 24 },
286-
"hasNext": { "type": "boolean", "example": true },
287-
"nextCursor": { "type": "string", "example": "eyJpZCI6MTIzLCJjcmVhdGVkX2F0IjoiMjAyNS0wNy0wMVQxMDowMDowMCJ9" },
288287
"items": {
289288
"type": "array",
290289
"items": {
@@ -326,6 +325,15 @@
326325
}
327326
}
328327
}
328+
},
329+
"pagination": {
330+
"type": "object",
331+
"properties": {
332+
"page": { "type": "integer", "example": 1 },
333+
"limit": { "type": "integer", "example": 12 },
334+
"totalCount": { "type": "integer", "example": 24 },
335+
"totalPages": { "type": "integer", "example": 2 }
336+
}
329337
}
330338
}
331339
}

0 commit comments

Comments
 (0)