NestJS에 Typeorm 설정
npm install @nestjs/typeorm typeorm pg
npm install @nestjs/typeorm typeorm pg 명령어는 다음과 같은 세 가지 패키지를 설치하는 것입니다. 각 패키지의 역할은 다음과 같습니다.
- @nestjs/typeorm:
- NestJS에서 TypeORM을 사용하기 위한 모듈입니다.
- NestJS는 데코레이터 기반의 ORM(Object-Relational Mapping) 라이브러리인 TypeORM과 함께 사용될 수 있도록 @nestjs/typeorm 패키지를 제공합니다.
- 이를 통해 NestJS 애플리케이션에서 데이터베이스와 쉽게 상호작용할 수 있으며, 모델을 클래스로 정의하고, 이를 데이터베이스 테이블과 매핑하여 데이터베이스 작업을 수행할 수 있습니다.
- typeorm:
- TypeORM 라이브러리 자체입니다.
- TypeORM은 Node.js 및 TypeScript에서 사용할 수 있는 ORM 라이브러리로, 데이터베이스의 테이블을 객체로 매핑하여 코드를 통해 데이터베이스를 다룰 수 있게 해줍니다.
- TypeORM은 다양한 데이터베이스(MySQL, PostgreSQL, SQLite, 등)를 지원하며, Repository 패턴, Entity, Migration 등의 기능을 제공합니다.
- pg:
- PostgreSQL 클라이언트 라이브러리입니다.
- pg 패키지는 TypeORM이 PostgreSQL 데이터베이스와 통신할 수 있도록 하는 드라이버 역할을 합니다.
- TypeORM은 **pg**를 통해 PostgreSQL 데이터베이스에 연결하고, 쿼리를 실행하며, 데이터 관리를 수행합니다.
설치가 다 끝나면 이제 nestjs 모듈에 넣어줘야 되는데
app.module.ts파일로 가서 임포트에 이렇게 적어줍니다.
imports: [
TypeOrmModule.forRoot({
// 데이터베이스 연결 설정을 초기화하는 TypeORM 설정 객체
type: 'postgres', // 데이터베이스의 타입. 여기서는 PostgreSQL을 사용
host: '127.0.0.1', // 데이터베이스 서버의 호스트 주소. 로컬에서 실행되는 데이터베이스를 사용
port: 5432, // 데이터베이스 서버의 포트 번호. PostgreSQL의 기본 포트는 5432
username: 'postgres', // 데이터베이스에 접근할 사용자 이름
password: 'postgres', // 데이터베이스에 접근할 때 사용하는 비밀번호
database: 'postgres', // 연결할 데이터베이스의 이름
entities: [
PostsModel, // 데이터베이스에서 관리될 엔티티(테이블) 목록. 여기서는 게시물 엔티티만 포함
],
synchronize: true, // 엔티티와 데이터베이스 스키마를 동기화하는 설정. true이면 애플리케이션이 실행될 때 데이터베이스 스키마가 자동으로 업데이트됨
}),
],
이렇게 하면 연동이 끝납니다
이제 엔티티를 만들어야 합니다
import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; // TypeORM에서 엔티티와 컬럼을 정의하는 데 필요한 데코레이터들을 불러옴
@Entity() // 이 클래스가 데이터베이스 테이블과 매핑될 엔티티임을 나타냄
export class PostsModel {
@PrimaryGeneratedColumn() // 기본 키로 사용될 열이며, 자동으로 증가하는 값으로 생성됨(PK)
id: number; // 게시물의 고유 ID (자동으로 생성되는 값)
@Column() // 일반 열을 나타내는 데코레이터, 데이터베이스에 문자열 형태로 저장됨
author: string; // 게시물 작성자의 이름 또는 ID
@Column()
title: string; // 게시물의 제목
@Column()
content: string; // 게시물의 내용
@Column()
likeCount: number; // 게시물이 받은 좋아요 수
@Column()
commentCount: number; // 게시물에 달린 댓글 수
}
@PrimaryGeneratedColum()은 숫자를 자동으로 증가시킬때 쓰는 PK이고
만약에 내가 PK값을 이메일로 하고싶다라고 가정하면
@PrimaryColumn() 이렇게해서 사용하면되고 당연히 email : string 이런식으로 설정해야합니다.
자동 증가기능은 없어지지만 PK로써 역할은 할 수 있습니다.
이제 작성이 끝나면 posts.module.ts파일을 열어서 임포트를 해줘야하는데
@Module({
imports:[
TypeOrmModule.forFeature([
PostsModel,
]),
],
controllers: [PostsController],
providers: [PostsService],
})
export class PostsModule { }
전에 app.module.ts에 임포트한건 forRoot이고 지금은 forFeature입니다.
- forRoot: 애플리케이션에서 데이터베이스 연결을 설정할 때 사용합니다. 주로 최상위 모듈(AppModule)에서 한 번만 호출하여, 데이터베이스 타입, 호스트, 포트, 사용자 이름, 비밀번호 등의 연결 설정을 정의합니다.
- TypeOrmModule.forRoot({ type: 'postgres', host: '127.0.0.1', port: 5432, username: 'postgres', password: 'postgres', database: 'postgres', synchronize: true, });
- forFeature: 특정 모듈에서 엔티티를 등록할 때 사용합니다. 예를 들어, **PostsModule**에서 PostsModel 엔티티를 사용할 수 있도록 등록할 때 **forFeature**를 사용합니다. 이는 해당 모듈에서만 이 엔티티를 통해 데이터베이스 작업을 할 수 있게 합니다.
- TypeOrmModule.forFeature([PostsModel]);
요약하자면, forRoot는 애플리케이션의 전역 데이터베이스 연결을 설정하고, forFeature는 특정 모듈에서 사용할 엔티티를 등록하는 역할을 합니다.
레포지토리라는걸 서비스에 주입한다음 데이터베이스를 사용해야죠
@Injectable() // 이 클래스가 NestJS의 의존성 주입 시스템에서 사용할 수 있는 서비스임을 나타냄
export class PostsService {
constructor(
@InjectRepository(PostsModel) // TypeORM의 `Repository` 객체를 `PostsModel` 엔티티에 대해 주입받기 위해 사용
private readonly postsRepository: Repository<PostsModel> // `PostsModel` 엔티티와 관련된 데이터베이스 작업을 수행하는 `postsRepository` 변수 정의
) {}
}
사용하려고 하는 postsService에 코드를 넣어줍니다.
근데 private readonly라고 하면 읽기전용아닌가? 그럼 데이터를 쓰기를 못하는건가? 라고 궁금해서 찾아봤는데
readonly 키워드는 변수 자체의 재할당을 방지하는 역할을 하며, 데이터의 읽기 전용성을 의미하지는 않습니다.
즉, **readonly**로 선언된 **postsRepository**는 해당 변수에 다른 레포지토리나 값을 할당할 수 없도록 고정되지만, 이 레포지토리를 통해 데이터를 추가, 수정, 삭제하는 작업은 여전히 가능합니다.
예를 들어, 아래와 같이 **postsRepository**를 사용하는 경우:
this.postsRepository.save(postData);// 데이터베이스에 새로운 게시물 저장 (쓰기 작업)
this.postsRepository.update(id, updatedData);// 게시물 수정 (쓰기 작업)
this.postsRepository.delete(id);// 게시물 삭제 (쓰기 작업)
이런 쓰기 작업은 readonly 속성과 관계없이 수행됩니다. **readonly**는 postsRepository 변수를 재할당할 수 없도록 할 뿐이며, 이 변수를 통해 데이터베이스 작업은 자유롭게 가능합니다.
따라서 **readonly**는 레포지토리 객체를 변경하지 않도록 보장하는 역할만 하며, 데이터 읽기와 쓰기 작업에 제한을 두지는 않습니다.
설정을 다하고 이제 코딩을 하면 잘됩니다
간단하게 create,save,findOne매서드로 만든 포스트 등록하는 것과 업데이트하는 것을 구현했습니다.
export interface PostModel {
id: number;
author: string;
title: string;
content: string;
likeCount: number;
commentCount: number;
}
@Injectable()
export class PostsService {
constructor(
@InjectRepository(PostsModel)
private readonly postsRepository: Repository<PostsModel>
) { }
async createPost(author: string, title: string, content: string) {
//1) => 저장할 객체를 생성한다.
//2) => 객체를 저장한다. (create 메서드에서 생성한 객체로)
const post = this.postsRepository.create({
author,
title,
content,
likeCount: 0,
commentCount: 0,
});
const newPost = await this.postsRepository.save(post);
return newPost;
}
async updatePost(postId: number, author: string, title: string, content: string) {
//save의 기능
// 1) 만약에 데이터가 존재하지 않는다면( id 기준으로 ) 새로 생성한다.
// 2) 만약에 데이터가 존재한다면 (같은 id 값이 존재한다면) 존재하던 값을 업데이트 한다.
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);
posts = posts.map(prevPost => prevPost.id === postId ? post : prevPost);
return newPost;
}
async deletePost(postId: number) {
const post = this.postsRepository.findOne({
where: {
id: postId
}
})
if (!post) {
throw new NotFoundException();
}
await this.postsRepository.delete(postId);
return postId;
}
}
'TypeOrm' 카테고리의 다른 글
TypeOrm Relationship (0) | 2024.11.09 |
---|---|
TypeOrm Inheritance (1) | 2024.11.08 |
TypeOrm Embedded Entity (0) | 2024.11.08 |
TypeOrm 엔티티 옵션 (0) | 2024.11.08 |
TypeOrm이 기본 개념 (1) | 2024.11.08 |