Try   HackMD
tags: NestJS typeORM

Nestjs - TypeORM Intergration

Nest提供@nestjs/typeorm套件來做TypeORM互動,因為TypeORM為TS中目前最成熟的ORM套件,他是用TS所寫的,所以能和Nest框架完美搭配。
以下會以MySQL為範例:
首先安裝套件:

$ npm install --save @nestjs/typeorm typeorm mysql2

安裝完後,將TypeOrmModule引入到AppModule

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'root',
      database: 'test',
      entities: [],
      synchronize: true,
    }),
  ],
})
export class AppModule {}

Setting synchronize: true shouldn't be used in production - otherwise you can lose production data.

當上面完成後,TypeORM的DataSourceEntityManager物件就可以在整個專案使用,如下:

import { DataSource } from 'typeorm';

@Module({
  imports: [TypeOrmModule.forRoot(), UsersModule],
})
export class AppModule {
  constructor(private dataSource: DataSource) {}
}

Repository pattern

TypeORM 支援repository design pattern,所以各個entity都有其repository,這些repository可以從database data source取得。
以下建立User Entity做示範:

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

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  firstName: string;

  @Column()
  lastName: string;

  @Column({ default: true })
  isActive: boolean;
}

為開始使用UserEntity,我們將其放入app.module內的forRoot() method的entities陣列內。

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './users/user.entity';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'root',
      database: 'test',
      entities: [User],
      synchronize: true,
    }),
  ],
})
export class AppModule {}

現在換看UsersModule:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  providers: [UsersService],
  controllers: [UsersController],
})
export class UsersModule {}

** 以下方式與文件不同,而是將與資料庫互動的部分從service拆分出來為一個*.repository.ts,而後在service中注入repository進而拆分權責,以便維護。 **

/// 從這後開始修改

這個module使用forFeature()來定義是哪個repositories被註冊在目前的scope,有了這個,我們就可以將UserRepository使用@InjectRepository()注入到UsersService中,如下:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UsersService {
  constructor(
    @InjectRepository(User)
    private usersRepository: Repository<User>,
  ) {}

  findAll(): Promise<User[]> {
    return this.usersRepository.find();
  }

  findOne(id: string): Promise<User> {
    return this.usersRepository.findOneBy({ id });
  }

  async remove(id: string): Promise<void> {
    await this.usersRepository.delete(id);
  }
}



如果你想要在外部的module使用此repository,你一樣必須要到module這裡把import的TypeOrmModule.forFeature再把他export:

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';

@Module({
  imports: [TypeOrmModule.forFeature([User])],
  exports: [TypeOrmModule]
})
export class UsersModule {}