본문 바로가기
개발일지/Nestjs

@EntityRepository()를 대신한 repository 생성 방법

by 한삐 2022. 12. 28.
728x90

 

 

새로운 토이 프로젝트를 만들면서 겸사겸사 백엔드 찍먹을 위해 nestjs를 이용해보려고 했다.

로컬 환경에서 CRUD를 만드는게 생각보다 간단해서, 본격적으로 DB와 연결을 시키려고 하니,

별도의 repository를 만들어 연동시켜줘야 한다고 한다.

 

일반적으로 nest는

request -> controller -> service -> controller -> response 순으로 작동하나,

DB와 관련된 일을 시키기 위해서는 repository를 생성해야한다고 한다. 즉,
request -> controller -> service -> repo* -> service ->  controller -> response
로 한 단계가 추가된다. (Repostitory pattern)

 

@EntityRepository를 통해 레포지토리를 설정해주는 방식이 많이 보였지만

 

 

사용하지 못한단다.

 

그래서 찾아낸 방법을 적용해봤다.

 

 

1. 기본 설정

 

config 설정

// src/configs/typeorm.configs.ts

export const typeORMConfig: TypeOrmModuleOptions = {
  // Database Type
  type: 'postgres', // 본인은 pg를 사용
  host: 'localhost',
  port: 5432,
  username: 'postgres', 
  password: 'password',
  database: 'database',
  entities: [__dirname + '/../**/*.entity.{js,ts}'], // 해당 경로 + 엔티티이름.entity.{js.ts}로 된 엔티티를 이용
  // autoLoadEntities: true, // 위와 다르게 entity들 알아서 찾아줌
  synchronize: true, // 배포할때 true 사용 시 데이터 삭제될 수 있음
};

 

config 설정 후 root 모듈에 import

 

// app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { PostlistModule } from './postlist/postlist.module';
import { typeORMConfig } from './configs/typeorm.configs';
import { TypeOrmModule } from '@nestjs/typeorm/dist';

@Module({
  imports: [
    TypeOrmModule.forRoot(typeORMConfig),
    PostlistModule,
  ],
  controllers: [AppController],
  providers: [],
})
export class AppModule {}

 

entity 생성

// src/postlist/entities/postlist.entity.ts

import { BaseEntity, Column, PrimaryGeneratedColumn, Entity } from 'typeorm';

@Entity()
export class Postlist extends BaseEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title: string;

  @Column()
  content: string;

  @Column()
  nickname: string;

  @Column()
  imageUrl?: string;
}

 

config 설정 시, entities에 이름을 ~~.entity.{js.ts}로 설정했는데

정작 entity 파일 이름이 설정해놓은 이름 형식과 다르면 [EntityMetadataNotFound] 에러를 띄우게되니,

설정한대로 이름을 잘 지어주기로 하자.

본인도 이것때문에 시간을 좀 날렸다.

 

https://github.com/typeorm/typeorm/issues/1327

 

{ EntityMetadataNotFound: No metadata for "User" was found. · Issue #1327 · typeorm/typeorm

Hello, I'm trying to setup a new project using the latest release and the ormconfig.yml options. I'm following the documentation and pointing it to the src/entity/*.js location, but i keep ...

github.com

 

 

2. custumRepository 만들기

 

src에 database 디렉토리를 만들어, 데코레이터와 모듈을 그 안에 넣어줬다.

 

// src/database/typeorm-ex.decorator.ts

import { SetMetadata } from '@nestjs/common';

export const TYPEORM_EX_CUSTOM_REPOSITORY = 'TYPEORM_EX_CUSTOM_REPOSITORY';

export function CustomRepository(entity: Function): ClassDecorator {
  return SetMetadata(TYPEORM_EX_CUSTOM_REPOSITORY, entity);
}


// typeorm-ex.module.ts

import { DynamicModule, Provider } from '@nestjs/common';
import { getDataSourceToken } from '@nestjs/typeorm';
import { DataSource } from 'typeorm';
import { TYPEORM_EX_CUSTOM_REPOSITORY } from './typeorm-ex.decorator';

export class TypeOrmExModule {
  public static forCustomRepository<T extends new (...args: any[]) => any>(
    repositories: T[],
  ): DynamicModule {
    const providers: Provider[] = [];

    for (const repository of repositories) {
      const entity = Reflect.getMetadata(
        TYPEORM_EX_CUSTOM_REPOSITORY,
        repository,
      );

      if (!entity) {
        continue;
      }

      providers.push({
        inject: [getDataSourceToken()],
        provide: repository,
        useFactory: (dataSource: DataSource): typeof repository => {
          const baseRepository = dataSource.getRepository<any>(entity);
          return new repository(
            baseRepository.target,
            baseRepository.manager,
            baseRepository.queryRunner,
          );
        },
      });
    }

    return {
      exports: providers,
      module: TypeOrmExModule,
      providers,
    };
  }
}

 

3. 사용할 repository 생성

// src/postlist/repository/postlist.repository.ts

import { CustomRepository } from 'src/database/typeorm-ex.decorator';
import { Repository } from 'typeorm';
import { Postlist } from '../entities/postlist.entity';

@CustomRepository(Postlist)
export class PostlistRepository extends Repository<Postlist> {}

 

4. module에 생성한 repository import

// src/postlist/postlist.module.ts

import { Module } from '@nestjs/common';
import { PostlistController } from './postlist.controller';
import { PostlistService } from './postlist.service';
import { PostlistRepository } from './repository/postlist.repository';
import { TypeOrmExModule } from 'src/database/typeorm-ex.module';

@Module({
  imports: [TypeOrmExModule.forCustomRepository([PostlistRepository])],
  controllers: [PostlistController],
  providers: [PostlistService],
})
export class PostlistModule {}

 

Module에 import 까지 해줬으니 이제 service 비즈니스 로직에만 repository를 넣어주면 된다.

 

// src/postlist/postlist.service.ts

import { Injectable, NotFoundException } from '@nestjs/common';
import { UpdatePostDto } from './dto/update-postlist.dto';

import { PostlistRepository } from './repository/postlist.repository';
import { Postlist } from './entities/postlist.entity';
import { CreatePostDto } from './dto/create-postlist.dto';

@Injectable()
export class PostlistService {
constructor(private readonly postlistRepository: PostlistRepository) {}
  
  async getAllPost(): Promise<Postlist[]> {
    const found = await this.postlistRepository.find();
    return found;
  }
  
  async getPostById(id: number): Promise<Postlist> {
    const found = await this.postlistRepository.findOne({ where: { id: id } });
    if (!found) {
      throw new NotFoundException(`Cannot find post with id ${id}`);
    }
    return found;
  }
}

// src/postlist/postlist.controller.ts

import { Body, Controller, Get, Param, Patch, Post } from '@nestjs/common';
import { CreatePostDto } from './dto/create-postlist.dto';
import { PostlistService } from './postlist.service';
import { UpdatePostDto } from './dto/update-postlist.dto';
import { Delete } from '@nestjs/common/decorators';
import { Postlist } from './entities/postlist.entity';

@Controller('postlist')
export class PostlistController {
  constructor(readonly postlistService: PostlistService) {}
  
  @Post()
  createOne(@Body() createPostDto: CreatePostDto): Promise<Postlist> {
    return this.postlistService.createPost(createPostDto);
  }

  @Get()
  getAll(): Promise<Postlist[]> {
    return this.postlistService.getAllPost();
  }

  @Get(':id')
  getOne(@Param('id') id: number): Promise<Postlist> {
    return this.postlistService.getPostById(id);
  }

  @Patch(':id')
  updateOne(
    @Param('id') id: number,
    @Body() updateData: UpdatePostDto,
  ): Promise<Postlist> {
    return this.postlistService.updatePost(id, updateData);
  }

  @Delete(':id')
  deleteOne(@Param('id') id: number): Promise<void> {
    return this.postlistService.deletePost(id);
  }
}

 

위와 같이 필요한 로직을 설정한 후 postman을 작동시켜주면 정상적으로 실행되는 것을 볼 수 있다.

 

 

필자는 nestjs 포트를 3001로 설정했지만, 보통은 3000일것이다.

 

 

 

DB 연결 b


 

참고 사이트

https://orkhan.gitbook.io/typeorm/readme_ko

 

README_ko - typeorm

 

orkhan.gitbook.io

https://docs.nestjs.com/techniques/database

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Progamming), FP (Functional Programming), and FRP (Functional Reac

docs.nestjs.com

 

728x90

댓글