목차


청사진 그리기

<aside>


Service, Controller

< service >

async function getMySales(userId, query) {
  // 1. 쿼리 문자열 검증
  const genre = query.genre ? Number(query.genre) : null;
  const grade = query.grade ? Number(query.grade) : null;
  const keyword = query.keyword || null;
  const saleType = query.saleType || null;
  const sale = query.sale || null;
  const page = query.page ? Math.max(1, parseInt(query.page, 10)) : 1;
  const size = query.size || 'md';
  const withCounts = true; // 우주: counts 요청 여부

  // 2. 검증
  if (genre && (genre < 1 || genre > 4)) {
    const error = new Error('장르 ID는 1~4 사이의 값이어야 합니다.');
    error.code = 400;
    throw error;
  }

  // 3. 페이지 계산
  const itemsPerPage = getItemsPerPage(size);
  const offset = (page - 1) * itemsPerPage;

  // 4. 데이터 조회
  const salesPromise = usersRepository.findMySales(userId, {
    genre, grade, keyword, saleType, sale, offset, limit: itemsPerPage
  });

	// 우주 님 코드 ↓ (여기서부터 ...까지)
  if (withCounts) {
    const [sales, counts] = await Promise.all([
      salesPromise,
      usersRepository.countSalesFilters(userId, {
        genre,
        grade,
        keyword,
        saleType,
        sale
      }) // 우주: 필터 카운트 병렬 조회
    ]);

    ...
    
  } else {
    const sales = await salesPromise;

    // 5. 페이지네이션 갱신
    const pagination = calculatePaginationDetails({
      totalItems: sales.totalItems,
      currentPage: page,
      size
    });

    return {
      items: sales.items,
      pagination
    };
  }
}

< controller >

usersController.get(
  '/cards-on-sale',
  passport.authenticate('access-token', { session: false, failWithError: true }),
  async (req, res, next) => {
    try {
      const userId = req.user.id;
      req.query.withCounts = 'true';
      const result = await usersService.getMySales(userId, req.query);
      res.json(result);
    } catch (err) {
      next(err);
    }
  }
);