[ TIL ] 02.23(목) 72일차

2023. 2. 23. 21:00· 코딩캠프/내일배움캠프
목차
  1. Nest.js 심화
  2. 5. 커스텀 리포지토리가 왜 필요한가?
  3. 6. 커스텀 리포지토리 만들기
728x90

Nest.js 심화

 

5. 커스텀 리포지토리가 왜 필요한가?

일반 리포지토리로도 기본적인 CRUD를 해야하지만 

경우에 따라서는 더 복잡한 연산 및 쿼리를 직접 정의해야 하는 경우가 있다

일반 리포지토리를 상속받은 커스텀 리포지토리를 작성하여 해결 할수있다.

 

💡 일반 리포지토리 기능을 상속받은 커스텀 쿼리가 가능한 리포지토리

 

6. 커스텀 리포지토리 만들기

Article 엔티티에 view 컬럼을 추가

article.entity.ts 수정

import {
Column,
CreateDateColumn,
DeleteDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
} from "typeorm";
@Entity({ schema: "board", name: "articles" })
export class Article {
@PrimaryGeneratedColumn({ type: "int", name: "id" })
id: number;
@Column("varchar", { length: 10 })
author: string;
@Column("varchar", { length: 50 })
title: string;
@Column("varchar", { length: 1000 })
content: string;
@Column("varchar", { length: 10, select: false })
password: string;
@Column("int")
view: number; // 새로 추가된 컬럼!
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date | null;
@DeleteDateColumn()
deletedAt: Date | null;
}

 

수정 후 서버를 시작 또는 재시작 하면

articles 테이블에 view 컬럼이 추가된다.

 

article.repository.ts 추가

import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { Article } from './article.entity';
@Injectable()
export class ArticleRepository extends Repository<Article> {
constructor(private dataSource: DataSource) {
super(Article, dataSource.createEntityManager());
}
async getArticlesByViewCount() {
const result = await this.createQueryBuilder()
.select('articles')
.from(Article, 'articles')
.orderBy('articles.view', 'DESC')
.getMany();
return result;
}
}

커스텀 리포지토리는 일반 리포지토리를 반드시 상속한다.

생성자의 매개변수로 DataSource타입의 변수가 들어가있다!!

 

DataSource는 데이터베이스 연결에 대한 추상화를 제공하는 클래스

데이터베이스 연결 정보를 감추고 쿼리를 실행하거나 트랜잭션을 관리할 수 있다

 

getArticlesByViewCount 라는

새로운 함수로 Repository에 있는 createQueryBuilder 함수를 통해서 Raw Query와 흡사하게 쿼리를 직접 작성

  • .select("article")
    • 선택할 테이블을 지정합니다.
  • .from(Article, "article")
    • 테이블 이름과 별칭을 설정합니다.
  • .orderBy("article.view", "DESC")
    • view 컬럼을 기준으로 결과를 내림차순으로 정렬합니다.
  • .getMany()
    • 쿼리를 실행하고 결과를 Article 객체의 배열로 반환합니다.

board.module.ts

providers 에  ArticleRepository 추가

import { ArticleRepository } from './article.repository';
providers: [BoardService, ArticleRepository], // ArticleRepository 추가!

 

 

board.controller.ts   

// 인기가 많은 순
@Get('/hot-articles')
async getHotArticles() {
return await this.boardService.getHotArticles();
}

 

 

 

board.service.ts

import {
Injectable,
NotFoundException,
UnauthorizedException,
} from '@nestjs/common';
import _ from 'lodash';
import { ArticleRepository } from './article.repository';
@Injectable()
export class BoardService {
constructor(private articleRepository: ArticleRepository) {}
async getArticles() {
return await this.articleRepository.find({
where: { deletedAt: null },
select: ['author', 'title', 'updatedAt'],
});
}
async getArticleById(id: number) {
return await this.articleRepository.findOne({
where: { id, deletedAt: null },
select: ['author', 'title', 'content', 'updatedAt'],
});
}
// 일반 리포지토리엔 없는 커스텀 리포지터리에만 있는 함수!
async getHotArticles() {
return await this.articleRepository.getArticlesByViewCount();
}
createArticle(title: string, content: string, password: number) {
this.articleRepository.insert({
// 일단 author는 test로 고정합니다.
author: 'test',
title,
content,
// password도 일단은 잠시 숫자를 문자열로 바꿉니다. 나중에 암호화된 비밀번호를 저장하도록 하겠습니다.
password: password.toString(),
});
}
async updateArticle(
id: number,
title: string,
content: string,
password: number,
) {
await this.verifyPassword(id, password);
this.articleRepository.update(id, { title, content });
}
async deleteArticle(id: number, password: number) {
await this.verifyPassword(id, password);
this.articleRepository.softDelete(id); // soft delete를 시켜주는 것이 핵심입니다!
}
private async verifyPassword(id: number, password: number) {
const article = await this.articleRepository.findOne({
where: { id, deletedAt: null },
select: ['password'],
});
if (_.isNil(article)) {
throw new NotFoundException(`Article not found. id: ${id}`);
}
if (article.password !== password.toString()) {
throw new UnauthorizedException(`Password is not corrected. id: ${id}`);
}
}
}
저작자표시 비영리 변경금지

'코딩캠프 > 내일배움캠프' 카테고리의 다른 글

[ WIL ] 02.20~24 15주차  (0) 2023.02.26
[ TIL ] 02.24(금) 73일차  (0) 2023.02.24
[ TIL ] 02.22(수) 71일차  (0) 2023.02.22
[ TIL ] 02.21(화) 70일차  (0) 2023.02.21
[ TIL ] 02.20(월) 69일차  (0) 2023.02.20
  1. Nest.js 심화
  2. 5. 커스텀 리포지토리가 왜 필요한가?
  3. 6. 커스텀 리포지토리 만들기
'코딩캠프/내일배움캠프' 카테고리의 다른 글
  • [ WIL ] 02.20~24 15주차
  • [ TIL ] 02.24(금) 73일차
  • [ TIL ] 02.22(수) 71일차
  • [ TIL ] 02.21(화) 70일차
고랑E
고랑E
300x250
고랑E
고랑의 개발일지
고랑E
전체
오늘
어제
  • 분류 전체보기 (209)
    • Project (18)
      • [팀] Color On Me (18)
      • [팀] Eats Finder (0)
    • Dev (14)
      • 네이버 클라우드 플랫폼(NCP) (3)
      • DB (3)
      • AWS (4)
      • GitHub (0)
    • Etc. (6)
      • 마인크래프트(Minecraft) (1)
      • 팰월드(PalWorld) (5)
    • 코딩캠프 (171)
      • 내일배움캠프 (99)
      • AI 웹개발 취업캠프 (72)

블로그 메뉴

  • 홈
  • 방명록
  • 글쓰기
  • 관리

공지사항

인기 글

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
고랑E
[ TIL ] 02.23(목) 72일차
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.