Accueil / Articles

Prisma 7 avec les adaptateurs de pilote NestJS et MySQL

Prisma 7 au sein d’un module global NestJS avec MySQL : le client TypeScript, prisma.config.ts ainsi que l’adaptateur du pilote MariaDB, connectés de manière à ce que chaque service en partage un seul.

Éditeur : REACTAPP.TOP5 min de lecture1112 mots

Sources: Get Started With Prisma 7 with Nest Js & MySQL

Prisma est un ORM pour Node.js et TypeScript qui gère les schémas, les relations et les requêtes typées. Prisma 7 modifie sa structure de fonctionnement : le chemin du client est plus simple à certains égards et plus strict à d’autres. L’objectif ici est de montrer comment intégrer Prisma 7 dans un service NestJS qui communique avec MySQL, et non de créer un squelette Nest complet à partir de zéro.

Quelles sont les modifications ?

  • Prisma Client ne fournit plus de binaires natifs en Rust.
  • Le chemin du client a été réécrit en TypeScript et s’exécute sur des environnements JS ordinaires.
  • Les fichiers générés par le client se trouvent dans la source du projet, et non uniquement sous node_modules.
  • La régénération du client ne nécessite plus de redémarrer le serveur de développement.
  • Un nouveau fichier de configuration Prisma est apparu.
  • Chaque base de données nécessite un adaptateur de pilote.
  • Le client généré est indépendant de la base de données : il se concentre sur la structure du schéma, et non sur un binaire d’engine intégré.
  • Prisma Studio peut être lancé via npx prisma studio.
  • Les enums mappés sont pris en charge.
    1. Installez les paquets Prisma 7 :
    npm install @prisma/client@7
    npm install -D prisma@7
    

    Prisma 7 ne charge pas automatiquement les variables d’environnement. Ajoutez dotenv :

    npm install dotenv
    

    Exemples de versions Node et npm utilisées dans les notes de configuration initiales :

    node -v
    v24.11.1
    npm -v
    11.6.2
    
    1. Créez la structure de base de Prisma :
    npx prisma init
    

    Cela crée un répertoire prisma contenant :

    • schema.prisma — connexion et modèles
    • prisma.config.ts — configuration
    • .env — généralement les identifiants de la base de données
    1. Installez un adaptateur MySQL/MariaDB (les adaptateurs sont abordés à nouveau à la fin) :
     npm install @prisma/adapter-mariadb
    
    1. Configurez l’URL, l’emplacement du schéma, le résultat de la migration et les données initiales. La documentation exige que prisma.config.ts se trouve dans la racine du projet à côté de package.json.

    .env :

    DATABASE_URL="mysql://test_user:test_password@localhost:3306/test_db"
    

    prisma.config.ts :

    // This file was generated by Prisma and assumes you have installed the following:
    // npm install --save-dev prisma dotenv
    import "dotenv/config";
    import { defineConfig, env } from "prisma/config";
    
    export default defineConfig({
      schema: "prisma/schema.prisma",
      migrations: {
        path: "prisma/migrations",
        seed: 'tsx prisma/seed.ts',
      },
      datasource: {
        url: process.env.DATABASE_URL!
      },
    });
    

    Un piège courant est l’erreur PrismaConfigEnvError: Variable d’environnement requise manquante : DATABASE_URL, ou des plaintes indiquant qu’une source de données est nécessaire pour prisma db push. Une discussion en cours peut être consultée sur prisma/prisma#28590.

    1. Définissez les résultats affichés par le client et les modèles dans le schéma :
    generator client {
      provider = "prisma-client"
      output   = "../src/generated/prisma"
      moduleFormat = "cjs" //Matches Prisma's output format with NestJS's CommonJS runtime environment.
    }
    
    datasource db {
      provider = "mysql"
    }
    
    // Example model
    model user {
      id        Int      @id @default(autoincrement())
      email     String   @unique
      name      String?
      password  String
      createdAt DateTime @default(now())
      updatedAt DateTime @updatedAt
    }
    
    1. Encadrez le client dans un service NestJS qui gère les opérations de connexion/déconnexion :
    import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
    import { PrismaClient } from '../src/generated/prisma/client';
    import { PrismaMariaDb } from '@prisma/adapter-mariadb';
    
    @Injectable()
    export class PrismaService
      extends PrismaClient
      implements OnModuleInit, OnModuleDestroy
    {
      constructor() {
        const adapter = new PrismaMariaDb(process.env.DATABASE_URL!);
        super({ adapter, log: ['info', 'warn', 'error'] });
      }
    
      async onModuleInit() {
        try {
          await this.$connect();
          await this.$queryRaw`SELECT 1`;
          console.log('✅ Prisma connected to MySQL');
        } catch (error) {
          console.error('❌ Prisma connection error:', error);
          throw error;
        }
      }
    
      async onModuleDestroy() {
        await this.$disconnect();
        console.log('🔌 Prisma disconnected from MySQL');
      }
    }
    
    1. Exportez-le depuis un module global :
    import { Module, Global } from '@nestjs/common';
    import { PrismaService } from './prisma.service';
    
    @Global()
    @Module({
      providers: [PrismaService],
      exports: [PrismaService],
    })
    export class PrismaModule {}
    
    1. Script de semence optionnel pour les données de test :
    import { PrismaClient } from '../src/generated/prisma/client';
    import { PrismaMariaDb } from '@prisma/adapter-mariadb';
    import 'dotenv/config';
    
    const adapter = new PrismaMariaDb(process.env.DATABASE_URL!);
    const prisma = new PrismaClient({ adapter });
    
    async function main() {
      console.log('🌱 Starting database seeding...');
    
      // Check if database already has data
      const userCount = await prisma.user.count();
    
      if (userCount > 0) {
        console.log('⚠️  Database already contains data. Skipping seed.');
        console.log(`   Found ${userCount} users in the database.`);
        return;
      }
    
      console.log('📭 Database is empty. Starting seed...');
    
      // Hash password for users
      const hashedPassword = 'test12345';
    
      // Create users
      const user1 = await prisma.user.create({
        data: {
          email: 'robot@gmail.com',
          name: 'Mr Robot',
          password: hashedPassword,
        },
      });
    
      console.log('✅ Created users');
    }
    
    main()
      .catch((e) => {
        console.error('❌ Error during seeding:', e);
        process.exit(1);
      })
      .finally(async () => {
        await prisma.$disconnect();
      });
    
    1. Importer PrismaModule dans le module racine :
    import { Module } from '@nestjs/common';
    import { AppController } from './app.controller';
    import { AppService } from './app.service';
    import { AuthModule } from './modules/auth/auth.module';
    import { ConfigModule } from '@nestjs/config';
    import { PrismaModule } from 'prisma/prisma.module';
    
    @Module({
      imports: [AuthModule, PrismaModule, ConfigModule.forRoot()],
      controllers: [AppController],
      providers: [AppService],
    })
    export class AppModule {}
    

    Avec la base de données en cours d’exécution :

    npx prisma generate
    npx prisma db push
    npx prisma db seed
    npm run start:dev
    

    Ignorer les fichiers générés dans git :

    /src/generated
    

    Structure typique des dossiers :

    └── 📁backend
        └── 📁prisma
            ├── prisma.module.ts
            ├── prisma.service.ts
            ├── schema.prisma
            ├── seed.ts
        └── 📁src
            └── 📁generated
                └── 📁prisma
            └── 📁modules
                └── 📁auth
            ├── app.controller.spec.ts
            ├── app.controller.ts
            ├── app.module.ts
            ├── app.service.ts
            ├── main.ts
        ├── .env
        ├── .gitignore
        ├── .prettierrc
        ├── eslint.config.mjs
        ├── nest-cli.json
        ├── package-lock.json
        ├── package.json
        ├── prisma.config.ts
        ├── README.md
        ├── tsconfig.build.json
        └── tsconfig.json
    

    Faire défiler les données localement :

    npx prisma studio
    

    Adaptateurs de pilote

    La version antérieure du Prisma Client reposait sur un moteur de requêtes Rust qui transformait les appels du client en SQL et établissait des connexions TCP à l’aide de pilotes intégrés. Prisma 7 déplace la compilation vers un compilateur de requêtes JavaScript et élimine ces pilotes intégrés. Les pilotes de base de données JavaScript communiquent avec la base de données ; des adaptateurs de pilotes assurent la traduction entre le compilateur et ces pilotes. Pour MySQL/MariaDB, utilisez l’adaptateur mariadb. Consultez la section des documents Prisma consacrée aux adaptateurs de pilotes de base de données pour obtenir la matrice actuelle.

    L’architecture NestJS bénéficie d’une seule instance de client partagée par processus. Créer un nouveau PrismaClient dans chaque gestionnaire de requête multiplie les connexions et rend les transactions plus difficiles à gérer. Le schéma de module global décrit ci-dessus maintient un service visible pour les modules fonctionnels tout en permettant aux tests de remplacer PrismaService par une version fictive.

    Lors de la régénération après des modifications du schéma, assurez-vous que le chemin output correspond toujours à l’import utilisé dans prisma.service.ts. Un désaccord entre le résultat du générateur et les chemins d’import est une cause fréquente d’erreurs du type « module non trouvé » après des exécutions réussies de prisma generate. Gardez moduleFormat en accord avec la manière dont Nest compile — les incohérences entre CommonJS et ESM se manifestent par des erreurs de runtime subtiles plutôt que par des échecs de compilation clairs.

    Cela suffit pour faire communiquer Prisma 7 avec MySQL depuis NestJS, en utilisant des adaptateurs, des fichiers de configuration et un client généré sous contrôle source.