TypeORM 이론
Typeorm
쉽게 테이블의 구조를 생성하기 위해서 사용함.
생성 방법
- 먼저 entity.ts 파일에 엔티티와 칼럼을 넣어주고 (PK 있어야 함
PrimaryGeneratedColumn) - app.module.ts 파일에 entities 에 새로 만든 클래스를 넣어준다.
// src/posts/entities/posts.entity.ts
import { Column, Entity } from "typeorm";
@Entity()
export class PostModel {
@PrimaryGeneratedColumn()
id: number;
@Column()
author: string;
@Column()
title: string;
@Column()
content: string;
@Column()
likeCount: number;
@Column()
commentCount: number;
}
// src/app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PostsModule } from './posts/posts.module';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
PostsModule,
TypeOrmModule.forRoot({
type: 'postgres',
host: '127.0.0.1',
port: 5432,
username: 'postgres',
password: 'postgres',
database: 'postgres',
entities: [PostsModel],
synchronize: true,
})
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
이렇게 생성된 것을 확인할 수 있다.
이제 연결을 해주어야한다.
위에서 생성한 DB 테이블 클래스인 PostsModel을 NestJS와 연결하는 과정이다.
- 이때
posts.module.ts파일에서TypeOrmModule.forFeature코드를 사용하는 이유는 다음과 같다.
"Nest야, 이 모듈(PostsModule)에서는
PostsModel이라는 설계도를 사용해서 DB에 접근할 거야. 그러니 이 모델을 관리할 수 있는 도구(Repository)를 준비해줘!"
posts.service.ts파일에서 Repository 주입하기
// posts.module.ts
@Module({
imports: [
TypeOrmModule.forFeature([
PostsModel,
])
],
controllers: [PostsController],
providers: [PostsService],
})
export class PostsModule {}
// posts.service.ts
@Injectable()
export class PostsService {
constructor(
@InjectRepository(PostsModel)
private readonly postsRepository: Repository<PostModel>) {}
GET
이제 getAllPosts 함수를 변경해보자.
async getAllPosts() {
this.postsRepository.find();
}
다음과 같이 Repository 를 사용하는데, 이때 find의 파라미터를 공백으로 넣으면 필터링을 거치지 않기 때문에 모든 데이터를 가져오게 된다.
다음은 getPostById 함수를 변경해보자.
MySQL 쿼리문처럼 조건을 찾기 위해서는 where 라는 키워드를 사용해야 한다.
데이터 존재 값 : 비교 값 형태로 코드를 작성해주면 된다.
(둘 다 변수명이 같을 경우에는 그냥 하나로 통합해서 써도 된다. id : id ⇒ id)
+) await 로 반환되기 때문에 Promise로 반환된다. 따라서 null이 아니기 때문에 에러가 잡히지 않는다. 이 부분을 주의해야한다.
// 변경 전
getPostById(id: number) {
const post = posts.find((post: PostModel) => post.id === +id);
if (!post) {
throw new NotFoundException();
}
return post;
}
// 변경 후
async getPostById(id: number) {
const post = await this.postsRepository.findOne({
where: {
id: id,
},
});
if (!post) {
throw new NotFoundException();
}
return post;
}
CREATE
- create 메서드 : 저장할 객체를 생성한다.
- save 메서드 : 객체를 저장한다. (create 메서드에서 생성한 객체로)
위에서 PostsModel 타입으로 데이터가 들어올 것이라고 선언해두었기 때문에 여기서는 바로 타입을 활용할 수 있게된다.
async createPost(author: string, title: string, content: string) {
const post = this.postsRepository.create({
author,
title,
content,
likeCount: 0,
commentCount: 0,
});
const newPost = await this.postsRepository.save(post);
return newPost;
}
이때 중요한 점은, 바로 id를 따로 입력하지 않았다는 점이다.
post 값으로 id를 입력하지 않은 채로 save를 했는데 postman을 확인해보면 id가 들어가있다.
자동으로 id가 생성이 된다는 것을 확인할 수 있었다.
이게 어떻게 가능한걸까?
바로 PK를 entity 선언 부분에서 따로 정해주었기 때문이다.
UPDATE
- SAVE
- 만약 데이터가 존재하지 않는다면 새로 생성한다.
- 만약 같은 id 값을 가진 데이터가 존재한다면 해당 데이터를 업데이트한다.
async updatePost(postId: number, author: string, title: string, content: string) {
const post = await this.postsRepository.findOne({
where: {
id: postId,
},
});
if (!post) {
throw new NotFoundException();
}
if (author) {
post.author = author;
}
if (title) {
post.title = title;
}
if (content) {
post.content = content;
}
const newPost = await this.postsRepository.save(post);
return newPost;
}
DELETE
async deletePost(id: number) {
const post = this.postsRepository.findOne({
where: {
id,
},
});
if (!post) {
throw new NotFoundException();
}
await this.postsRepository.delete(id);
return id;
}