Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/features/user/repositories/user.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,9 @@ export class UserRepository {

/**
* 주어진 productIds 중 사용자가 찜한 것들의 product_id 집합을 단일 IN 쿼리로 반환.
* 매핑(N+1 회피)용.
* 매핑(N+1 회피)용. 가시성 조건(visibleWishlistWhere)을 myWishlist/wishlistCount와
* 공유하여, recent-view 등에 노출되는 isWishlisted 플래그가 실제 wishlist 표면
* (목록/카운트)과 일관되도록 한다.
*/
async findWishlistedProductIds(args: {
accountId: bigint;
Expand All @@ -443,8 +445,7 @@ export class UserRepository {
if (args.productIds.length === 0) return new Set();
const rows = await this.prisma.wishlistItem.findMany({
where: {
account_id: args.accountId,
deleted_at: null,
...this.visibleWishlistWhere(args.accountId),
product_id: { in: args.productIds },
},
select: { product_id: true },
Expand Down Expand Up @@ -478,7 +479,8 @@ export class UserRepository {
const [rows, totalCount] = await this.prisma.$transaction([
this.prisma.wishlistItem.findMany({
where,
orderBy: { created_at: 'desc' },
// 같은 밀리초 생성 시 페이지 경계 흔들림 방지를 위해 product_id를 보조 정렬키로 둔다.
orderBy: [{ created_at: 'desc' }, { product_id: 'desc' }],
skip: args.offset,
take: args.limit,
select: {
Expand Down
28 changes: 28 additions & 0 deletions src/features/user/services/user-recent-view.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,34 @@ describe('UserRecentViewService (real DB)', () => {
expect(map.get(notWishlisted.id.toString())).toBe(false);
});

it('비활성 store/product에 대한 wishlist는 isWishlisted=false로 매핑된다 (myWishlist 가시성과 일치)', async () => {
const account = await createAccount(prisma, { account_type: 'USER' });
const inactiveStore = await createStore(prisma, { is_active: false });
const productOfInactiveStore = await createProduct(prisma, {
store_id: inactiveStore.id,
});
// recent-view 항목으로는 보이지만, 그 product의 store가 비활성이라
// myWishlist에는 노출되지 않음 → isWishlisted도 false여야 일관됨
await createRecentProductView(prisma, {
account_id: account.id,
product_id: productOfInactiveStore.id,
});
await prisma.wishlistItem.create({
data: {
account_id: account.id,
product_id: productOfInactiveStore.id,
},
});

const result = await service.list(account.id);

expect(result.items).toHaveLength(1);
expect(result.items[0].productId).toBe(
productOfInactiveStore.id.toString(),
);
expect(result.items[0].isWishlisted).toBe(false);
});

it('pagination: offset + limit < totalCount면 hasMore true', async () => {
const account = await createAccount(prisma, { account_type: 'USER' });
const store = await createStore(prisma);
Expand Down
Loading