TypeOrm を追加する
はじめに
今回は TypeOrm を追加して Database にアクセスできるようにしますよ。
Angular 10 + NgRx + Nest.js でプロジェクトを作る
TypeOrm を使う
Install
前回と同じくいくつかパッケージをインストールします。
Nest.js のプロジェクトに統合するためのパッケージもあるので合わせてインストールします。
npm install --save @nestjs/typeorm typeorm pg
Configuration
前回は「ormconfig.json」を使って TypeOrm の設定( Database の接続文字列など)を行っていました。
Nest.js のプロジェクトでは、「app.module.ts」の中で設定することもできます。
server/app.module.ts
import { Module } from '@nestjs/common';
import { AngularUniversalModule } from '@nestjs/ng-universal';
import { TypeOrmModule } from '@nestjs/typeorm';
import { join } from 'path';
import { Workflow } from './entities/workflow.entity';
@Module({
imports: [
AngularUniversalModule.forRoot({
viewsPath: join(process.cwd(), 'dist/browser'),
bundle: require('../server/main'),
liveReload: false
}),
TypeOrmModule.forRoot({
type: "postgres",
host: "localhost",
port: 5432,
username: "test",
password: "test",
database: "Example",
entities: [Workflow],
synchronize: true,
logging: true,
cache: false
})
],
controllers: [],
providers: []
})
export class ApplicationModule {}
結局 JSON ファイルを選択した
結局、前回同様「ormconfig.json」を使うことにしました。
理由は、マイグレーションファイルを使った Database 更新をしたい場合、 TypeOrm のコマンドを使うのですが、この時コマンドからは「app.module.ts」の内容が参照できません(多分)。
ということで、いずれにしても「ormconfig.json」が必要になるわけですね。
ormconfig.json
{
"type": "postgres",
"host": "localhost",
"port": 5432,
"username": "test",
"password": "test",
"database": "Example",
"entities": ["dist/**/entities/*.entity{.ts,.js}"],
"migrations": ["server/migrations/*.{.ts,.js}"],
"synchronize": true,
"logging": true,
"cache": false,
"cli": {
"entitiesDir": "server/entities",
"migrationsDir": "server/migrations"
}
}
なお「ormconfig.json」を使う場合の「app.module.ts」はこんな感じです。
server/app.module.ts
~省略~
@Module({
imports: [
~省略~
TypeOrmModule.forRoot()
],
controllers: [],
providers: []
})
export class ApplicationModule {}
Entity クラスを追加する
server/entities/workflow.entity.ts
import {Entity, PrimaryGeneratedColumn, Column, OneToMany, UpdateDateColumn} from "typeorm";
@Entity("Workflow")
export class Workflow {
@PrimaryGeneratedColumn()
id: number = -1;
@Column({ type: 'text', nullable: false })
createUserMail: string = '';
@Column({ type: 'timestamp with time zone', nullable: true })
circulationLimit: Date|null = null;
@Column({ type: 'timestamp with time zone', nullable: false })
lastUpdateDate: Date = new Date();
public create(createUserMail: string, circulationLimit: Date|null) {
if (createUserMail == null ||
createUserMail.length <= 0) {
throw new Error("Can not set createUserMail empty");
}
this.createUserMail = createUserMail;
this.update(circulationLimit);
}
public update(circulationLimit: Date|null) {
this.circulationLimit = circulationLimit;
this.lastUpdateDate = new Date();
}
}
「nest generate」を使う
TypeOrm のクラスにアクセスするため、いくつか Nest.js のプロジェクトにクラスを追加していきます。
が、「nest generate ~」を実行すると、ファイルが「src」ディレクトリにできてしまう。。。(´・ω・`)
サーバー側のファイルを置いている「server」ディレクトリ以下にファイルを出力するにはどうすれば・・・?
結果としては、プロジェクト直下に「nest-cli.json」を置くことで解決しました。
nest-cli.json
{
"collection": "@nestjs/schematics",
"sourceRoot": "server"
}
「@nestjs/testing」の追加
Controller や Service などのクラスを追加したところ、エラー発生。
どうも一緒に追加されたテストクラスが必要としている、「@nestjs/testing」が足りない模様。
ということでインストールしました。
npm install --save-dev @nestjs/testing
Repository クラスから Database にアクセスする
Database にアクセスする(失敗)
まず Database にアクセスするための Controller や Service を追加します。
server/workflow/workflow.controller.ts
import { Controller, Get } from '@nestjs/common';
import { WorkflowService } from './workflow.service';
import { Workflow } from '../entities/workflow.entity';
@Controller('workflow')
export class WorkflowController {
constructor(private readonly service: WorkflowService) {
}
@Get("search")
public async getWorkflowItems(): Promise<Workflow[]> {
return await this.service.findAll();
}
}
server/workflow/workflow.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Workflow } from '../entities/workflow.entity';
import { Repository } from 'typeorm';
import { of } from 'rxjs';
@Injectable()
export class WorkflowService {
constructor(
@InjectRepository(Workflow)
private workflowRepositiory: Repository<Workflow>
){}
public findAll(): Promise<Workflow[]> {
return this.workflowRepositiory.find();
}
}
server/app.module.ts
...
import { WorkflowController } from './workflow/workflow.controller';
import { WorkflowService } from './workflow/workflow.service';
import { Workflow } from './entities/workflow.entity';
@Module({
imports: [
...
],
controllers: [WorkflowController],
providers: [WorkflowService]
})
export class ApplicationModule {}
OK。では実行してみます。
…エラーが発生しました(´・ω・`)
... [Nest] 17376 - 07/11/2020, 8:22:27 PM [ExceptionHandler] Nest can't resolve dependencies of the WorkflowService (?). Please make sure that the argument WorkflowRepository at index [0] is available in the ApplicationModule context. Potential solutions: - If WorkflowRepository is a provider, is it part of the current ApplicationModule? - If WorkflowRepository is exported from a separate @Module, is that module imported within ApplicationModule? @Module({ imports: [ /* the Module containing WorkflowRepository */ ] }) +570ms Error: Nest can't resolve dependencies of the WorkflowService (?). Please make sure that the argument WorkflowRepository at index [0] is available in the ApplicationModule context. Potential solutions: - If WorkflowRepository is a provider, is it part of the current ApplicationModule? - If WorkflowRepository is exported from a separate @Module, is that module imported within ApplicationModule? @Module({ imports: [ /* the Module containing WorkflowRepository */ ] }) at Injector.lookupComponentInParentModules (C:\Users\example\Documents\workspace\proofreading-workflow\node_modules\@nestjs\core\injector\injector.js:190:19) at processTicksAndRejections (internal/process/task_queues.js:97:5) [nodemon] app crashed - waiting for file changes before starting...
依存を解決する
どうも Repository クラスが DI できてないようです。
結局「app.module.ts」にモジュールを追加しました。
server/app.module.ts
...
import { Workflow } from './entities/workflow.entity';
@Module({
imports: [
...
TypeOrmModule.forRoot(),
TypeOrmModule.forFeature([Workflow])
],
controllers: [ProofreaderController, WorkflowController],
providers: [ProofreaderService, WorkflowService]
})
export class ApplicationModule {}
ようやく Database にアクセスできるようになりました :).