Passer au contenu

SQL (Sequelize)

Ce chapitre s’applique uniquement à TypeScript

Sequelize est un ORM populaire écrit en JavaScript vanilla, mais il existe un wrapper TypeScript sequelize-typescript qui fournit un ensemble de décorateurs et d’autres extras pour le sequelize de base.

Getting started

Pour commencer l’aventure avec cette bibliothèque, nous devons installer les dépendances suivantes :

Fenêtre de terminal
$ npm install --save sequelize sequelize-typescript mysql2
$ npm install --save-dev @types/sequelize

La première étape consiste à créer une instance de Sequelize avec un objet options transmis au constructeur. De plus, nous devons ajouter tous les modèles (l’alternative est d’utiliser la propriété modelPaths) et de synchroniser notre base de données.

database.providers.ts
import { Sequelize } from 'sequelize-typescript';
import { Cat } from '../cats/cat.entity';
export const databaseProviders = [
{
provide: 'SEQUELIZE',
useFactory: async () => {
const sequelize = new Sequelize({
dialect: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'password',
database: 'nest',
});
sequelize.addModels([Cat]);
await sequelize.sync();
return sequelize;
},
},
];

Ensuite, nous devons exporter ces fournisseurs pour les rendre accessibles au reste de l’application.

database.module.ts
import { Module } from '@nestjs/common';
import { databaseProviders } from './database.providers';
@Module({
providers: [...databaseProviders],
exports: [...databaseProviders],
})
export class DatabaseModule {}

Maintenant, nous pouvons injecter l’objet Sequelize en utilisant le décorateur @Inject(). Chaque classe qui dépendra du fournisseur asynchrone Sequelize attendra qu’une Promise soit résolue.

Model injection

Dans Sequelize, le Model définit une table dans la base de données. Les instances de cette classe représentent une ligne de la base de données. Tout d’abord, nous avons besoin d’au moins une entité :

cat.entity.ts
import { Table, Column, Model } from 'sequelize-typescript';
@Table
export class Cat extends Model {
@Column
name: string;
@Column
age: number;
@Column
breed: string;
}

L’entité Cat appartient au répertoire cats. Ce répertoire représente le CatsModule. Maintenant, il est temps de créer un fournisseur de Repository :

cats.providers.ts
import { Cat } from './cat.entity';
export const catsProviders = [
{
provide: 'CATS_REPOSITORY',
useValue: Cat,
},
];

Dans Sequelize, nous utilisons des méthodes statiques pour manipuler les données, et donc nous avons créé un alias ici.

Maintenant, nous pouvons injecter le CATS_REPOSITORY dans le CatsService en utilisant le décorateur @Inject() :

cats.service.ts
import { Injectable, Inject } from '@nestjs/common';
import { CreateCatDto } from './dto/create-cat.dto';
import { Cat } from './cat.entity';
@Injectable()
export class CatsService {
constructor(
@Inject('CATS_REPOSITORY')
private catsRepository: typeof Cat
) {}
async findAll(): Promise<Cat[]> {
return this.catsRepository.findAll<Cat>();
}
}

La connexion à la base de données est asynchrone, mais Nest rend ce processus complètement invisible pour l’utilisateur final. Le fournisseur CATS_REPOSITORY attend la connexion à la base de données, et le CatsService est retardé jusqu’à ce que le repository soit prêt à être utilisé. L’ensemble de l’application peut démarrer lorsque chaque classe est instanciée.

Voici un module final CatsModule :

cats.module.ts
import { Module } from '@nestjs/common';
import { CatsController } from './cats.controller';
import { CatsService } from './cats.service';
import { catsProviders } from './cats.providers';
import { DatabaseModule } from '../database/database.module';
@Module({
imports: [DatabaseModule],
controllers: [CatsController],
providers: [
CatsService,
...catsProviders,
],
})
export class CatsModule {}