NestJS | NestJS에서 Sequelize 사용하기(feat. PostgreSQL)

Sua·2024년 3월 3일
0

NestJS

목록 보기
9/9
post-custom-banner

NestJS에서 TypeORM을 사용해보았으나 Sequelize가 낫다고 판단했다. TypeORM에서 복잡한 쿼리는 쿼리 빌더(query builder)를 사용해야 하는 불편함이 있었고, Sequelize에 비해 쿼리 최적화를 잘 못해준다는 문제가 있었다.

NestJS 적용 - sequelize-typescript

NestJS에서 Sequelize를 사용하기 위해서 sequelize-typescript 패키지를 설치한다.

// app.module.ts
@Module({
  imports: [
    SequelizeModule.forRoot({
      dialect: 'postgres',
      name: 'now-db',
      host: env.NOW_DB_HOST,
      port: env.NOW_DB_PORT || 5432,
      username: env.NOW_DB_USERNAME,
      password: env.NOW_DB_PASSWORD,
      database: env.NOW_DB_DATABASE,
      models: [User], // <- 사용할 모델 등록
      autoLoadModels: false,
  	}),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}
// user.model.ts
@Table({ tableName: 'users' })
export class User extends Model<User> {
  @Column(DataType.STRING(100))
  name: string
  
  @Column(DataType.STRING(30))
  password: string
  
  @AllowNull
  @Column(DataType.STRING(30))
  email?: string | null
}
// user.service.ts
@Injectable()
export class UserService {
  constructor(
    @InjectModel(User)
    private readonly userModel: typeof User,
  ) {}

  async findUsers() {
    return this.userModel.findAll();
  }
}

여러 개 데이터베이스 연결하기

만약 now-db가 아닌 next-db라는 데이터베이스를 추가하고 싶다면 아래와 같이 수정한다.

// app.module.ts
@Module({
  imports: [
    SequelizeModule.forRoot({
      dialect: 'postgres',
      name: 'now-db',
      host: env.NOW_DB_HOST,
      port: env.NOW_DB_PORT || 5432,
      username: env.NOW_DB_USERNAME,
      password: env.NOW_DB_PASSWORD,
      database: env.NOW_DB_DATABASE,
      models: [User], 
      autoLoadModels: false,
  	}),
    SequelizeModule.forRoot({ // <- next-db 추가
      dialect: 'postgres',
      name: 'next-db',
      host: env.NEXT_DB_HOST,
      port: env.NEXT_DB_PORT || 5432,
      username: env.NEXT_DB_USERNAME,
      password: env.NEXT_DB_PASSWORD,
      database: env.NEXT_DB_DATABASE,
      models: [Item], 
      autoLoadModels: false,
  	}),
  ],
  controllers: [],
  providers: [],
})
export class AppModule {}
// item.model.ts
@Table({ tableName: 'items' })
export class Item extends Model<Item> {
  @Column(DataType.STRING(300))
  name: string
  
  @Column(DataType.STRING(300))
  code: string
  
  @AllowNull
  @Column(DataType.DECIMAL)
  price?: string | null
}
// user.service.ts
@Injectable()
export class UserService {
  constructor(
    @InjectModel(User, 'now-db') // <- DB명 추가
    private readonly userModel: typeof User,
  ) {}
  
  async findUsers() {
    return this.userModel.findAll();
  }
}
// item.service.ts
@Injectable()
export class ItemService {
  constructor(
    @InjectModel(Item, 'next-db') // <- DB명 추가
    private readonly itemModel: typeof Item,
    @InjectConnection('next-db') // <- Raw 쿼리 사용하고 싶을 경우
    private readonly sequelizeConnection: Sequelize,
  ) {}
  
  async findItems() {
    return this.sequelizeConnection.query(`SELECT id, name, code, price FROM items`, {
      type: QueryTypes.SELECT,
    })
  }
}

팁: 기존 DB 스키마로 model 만들기

TypeORM의 entity처럼 sequelize-typescript를 사용하기 위해서는 model을 작성해줘야 한다. 기존에 생성된 데이터베이스의 스키마를 모델로 작성하는 일이 여간 귀찮은 일이 아니기에 간단한 스니펫을 만들어 사용하면 편하다.

import { DialectPostgres, IConfig, ModelBuilder } from 'sequelize-typescript-generator'

(async () => {
  const schema = 'common' // <- postgres 스키마 사용 시 추가
  const config: IConfig = {
    connection: {
      dialect: 'postgres',
      host: 'localhost',
      database: 'test',
      username: 'user1',
      password: 'testpw',
    },
    metadata: {
      indices: false,
      case: 'CAMEL',
      schema,
      tables: ['table1', 'table2'], // <- 테이블명 변경
    },
    output: {
      clean: true,
      outDir: './src/model', // <- 저장하고 싶은 경로
    },
    strict: true,
  }

  const dialect = new DialectPostgres()

  const builder = new ModelBuilder(config, dialect)

  try {
    await builder.build()
  }
  catch (err) {
    console.error(err)
    process.exit(1)
  }
})()

위 코드를 model-generator.ts 라는 파일로 저장 후 아래 명령어로 실행한다.

ts-node model-generator.ts

나오는 결과물을 입맛에 맞게 수정해서 사용해도 되고, 직접 모델을 작성해줘도 된다.

profile
Leave your comfort zone
post-custom-banner

0개의 댓글