SQL (TypeORM)
Ce chapitre s’applique uniquement à TypeScript
TypeORM est sans doute le Mapper Relationnel Objet (ORM) le plus mature disponible dans le monde Node.js. Puisqu’il est écrit en TypeScript, il fonctionne très bien avec le framework Nest.
Prise en main
Pour commencer cette aventure avec cette bibliothèque, nous devons installer toutes les dépendances requises :
$ npm install --save typeorm mysql2
La première étape consiste à établir la connexion avec notre base de données en utilisant la classe new DataSource().initialize()
importée depuis le package typeorm
. La fonction initialize()
retourne une Promise
, et par conséquent, nous devons créer un fournisseur asynchrone.
import { DataSource } from 'typeorm';
export const databaseProviders = [ { provide: 'DATA_SOURCE', useFactory: async () => { const dataSource = new DataSource({ type: 'mysql', host: 'localhost', port: 3306, username: 'root', password: 'root', database: 'test', entities: [ __dirname + '/../**/*.entity{.ts,.js}', ], synchronize: true, });
return dataSource.initialize(); }, },];
Ensuite, nous devons exporter ces fournisseurs pour les rendre accessibles au reste de l’application.
import { Module } from '@nestjs/common';import { databaseProviders } from './database.providers';
@Module({ providers: [...databaseProviders], exports: [...databaseProviders],})export class DatabaseModule {}
Maintenant, nous pouvons injecter l’objet DATA_SOURCE
en utilisant le décorateur @Inject()
. Chaque classe qui dépendra du fournisseur asynchrone DATA_SOURCE
attendra jusqu’à ce qu’une Promise
soit résolue.
Modèle de dépôt
TypeORM prend en charge le modèle de conception de dépôt, donc chaque entité a son propre dépôt. Ces dépôts peuvent être obtenus à partir de la connexion à la base de données.
Mais d’abord, nous avons besoin d’au moins une entité. Nous allons réutiliser l’entité Photo
de la documentation officielle.
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()export class Photo { @PrimaryGeneratedColumn() id: number;
@Column({ length: 500 }) name: string;
@Column('text') description: string;
@Column() filename: string;
@Column('int') views: number;
@Column() isPublished: boolean;}
L’entité Photo
appartient au répertoire photo
. Ce répertoire représente le PhotoModule
. Maintenant, créons un fournisseur Repository :
import { DataSource } from 'typeorm';import { Photo } from './photo.entity';
export const photoProviders = [ { provide: 'PHOTO_REPOSITORY', useFactory: (dataSource: DataSource) => dataSource.getRepository(Photo), inject: ['DATA_SOURCE'], },];
Nous pouvons maintenant injecter le Repository<Photo>
dans le PhotoService
en utilisant le décorateur @Inject()
:
import { Injectable, Inject } from '@nestjs/common';import { Repository } from 'typeorm';import { Photo } from './photo.entity';
@Injectable()export class PhotoService { constructor( @Inject('PHOTO_REPOSITORY') private photoRepository: Repository<Photo>, ) {}
async findAll(): Promise<Photo[]> { return this.photoRepository.find(); }}
La connexion à la base de données est asynchrone, mais Nest rend ce processus complètement invisible pour l’utilisateur final. Le PhotoRepository
attend la connexion à la base de données, et le PhotoService
est retardé jusqu’à ce que le dépôt soit prêt à être utilisé. L’application entière peut démarrer lorsque chaque classe est instanciée.
Voici un module PhotoModule
final :
import { Module } from '@nestjs/common';import { DatabaseModule } from '../database/database.module';import { photoProviders } from './photo.providers';import { PhotoService } from './photo.service';
@Module({ imports: [DatabaseModule], providers: [ ...photoProviders, PhotoService, ],})export class PhotoModule {}