前回
TypeORMのマイグレーションについて
モデルが変更される場合、それをデータベースに同期する必要があります。
synchronize: true
というオプションをルートモジュールで設定していましたが、これはEntityに基づいてテーブルを自動生成してくれるオプションです。
そのため、本番環境ではこのオプションはfalseに設定しておくべきです。
Sequelize統合
TypeORMを使用する代わりに、Sequelize ORMを使用することもできます。
以下をインストールします。
$ npm install --save @nestjs/sequelize sequelize sequelize-typescript mysql2 $ npm install --save-dev @types/sequelize
ルートモジュールに組み込みます。
src/app.module.ts
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common"; import { TypeOrmModule } from "@nestjs/typeorm"; import { AppController } from "./app.controller"; import { AppService } from "./app.service"; import { CatsController } from "./cats/cats.controller"; import { CatsModule } from "./cats/cats.module"; import { logger } from "./middleware/logger/logger.middleware"; import { UserModule } from "./user/user.module"; import { SequelizeModule } from "@nestjs/sequelize"; @Module({ imports: [ TypeOrmModule.forRoot({ type: "mysql", host: "localhost", port: 3306, username: "root", password: "root", database: "test", synchronize: true, autoLoadEntities: true, }), SequelizeModule.forRoot({ dialect: "mysql", host: "localhost", port: 3306, username: "root", password: "root", database: "test", models: [], }), CatsModule, UserModule, ], controllers: [AppController], providers: [AppService], }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(logger).forRoutes(CatsController); } }
SequelizeModule.forRoot
を追加しました。
サービスにDIしてみます。
src/user/user.service.ts
import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { Sequelize } from "sequelize"; import { DataSource, DeleteResult, Repository } from "typeorm"; import { CreateUserDto } from "./dto/create-user.dto"; import { UpdateUserDto } from "./dto/update-user.dto"; import { User } from "./entities/user.entity"; @Injectable() export class UserService { constructor( @InjectRepository(User) private userRepository: Repository<User>, private dataSource: DataSource, private sequelize: Sequelize ) {}
Sequelize モデル
SequelizeはActive Recordパターンで実装します。
このパターンでは、モデルクラスを直接使用してデータベースを操作します。
モデルを作成します。
src/user/user.model.ts
import { Column, PrimaryKey, Table, Model } from "sequelize-typescript"; @Table export class User extends Model { @PrimaryKey id: number; @Column firstName: string; @Column lastName: string; @Column({ defaultValue: true }) isActive: boolean; }
ルートモジュールに作成したモデルを追加します。
src/app.module.ts
import { MiddlewareConsumer, Module, NestModule } from "@nestjs/common"; import { TypeOrmModule } from "@nestjs/typeorm"; import { AppController } from "./app.controller"; import { AppService } from "./app.service"; import { CatsController } from "./cats/cats.controller"; import { CatsModule } from "./cats/cats.module"; import { logger } from "./middleware/logger/logger.middleware"; import { UserModule } from "./user/user.module"; import { SequelizeModule } from "@nestjs/sequelize"; import { User } from "./user/user.model"; @Module({ imports: [ TypeOrmModule.forRoot({ type: "mysql", host: "localhost", port: 3306, username: "root", password: "root", database: "test", synchronize: true, autoLoadEntities: true, }), SequelizeModule.forRoot({ dialect: "mysql", host: "localhost", port: 3306, username: "root", password: "root", database: "test", models: [User], }), CatsModule, UserModule, ], controllers: [AppController], providers: [AppService], }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(logger).forRoutes(CatsController); } }
その後、ユーザモジュールに組み込みます。
src/user/user.module.ts
import { Module } from "@nestjs/common"; import { UserService } from "./user.service"; import { UserController } from "./user.controller"; import { TypeOrmModule } from "@nestjs/typeorm"; import { UserSchema } from "./user.schema"; import { PhotoSchema } from "src/photo/photo.schema"; import { SequelizeModule } from "@nestjs/sequelize"; import { User } from "./user.model"; @Module({ imports: [ TypeOrmModule.forFeature([UserSchema, PhotoSchema]), SequelizeModule.forFeature([User]), ], controllers: [UserController], providers: [UserService], }) export class UserModule {}
SequelizeModule.forFeature([User]),
を追加しました。
これをサービスに適用できます。
src/user/user.service.ts
import { Injectable } from "@nestjs/common"; import { InjectRepository } from "@nestjs/typeorm"; import { DataSource, Repository } from "typeorm"; import { CreateUserDto } from "./dto/create-user.dto"; import { UpdateUserDto } from "./dto/update-user.dto"; import { User } from "./entities/user.entity"; import { User as UserModel } from "./user.model"; @Injectable() export class UserService { constructor( @InjectRepository(User) private userRepository: Repository<User>, private dataSource: DataSource, private userModel: typeof UserModel ) {} create(createUserDto: CreateUserDto) { return "This action adds a new user"; } async createMany(users: User[]) { const queryRunner = this.dataSource.createQueryRunner(); await queryRunner.connect(); await queryRunner.startTransaction(); try { await queryRunner.manager.save(users[0]); await queryRunner.manager.save(users[1]); await queryRunner.commitTransaction(); } catch (error) { await queryRunner.rollbackTransaction(); } finally { await queryRunner.release(); } } async findAll(): Promise<UserModel[]> { return this.userModel.findAll(); } findOne(id: number): Promise<UserModel> { return this.userModel.findOne({ where: { id, }, }); } update(id: number, updateUserDto: UpdateUserDto) { return `This action updates a #${id} user`; } async remove(id: number): Promise<void> { const user = await this.findOne(id); await user.destroy(); } }
全体的にuserModelに変更しました。
まとめ
ここまでで、
- TypeORMのマイグレーションについて
- Sequelize統合について
- Sequelize モデルについて
を学びました。
データベース操作できるようになったので、これで終わろうと思います。
コード
今回のコードは、以下に格納しました。