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 |