Inicio / Artículos

Prisma 7 con adaptadores de controlador para NestJS y MySQL

Prisma 7 dentro de un módulo global de NestJS con MySQL: el cliente de TypeScript, prisma.config.ts y el adaptador del controlador MariaDB, conectados de modo que cada servicio comparta el mismo.

Editor: REACTAPP.TOP5 min de lectura1112 palabras

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

Prisma es un ORM para Node.js y TypeScript que gestiona esquemas, relaciones y consultas tipadas. Prisma 7 modifica la estructura del entorno de ejecución: el camino del cliente es más simple en algunos aspectos y más estricto en otros. El foco aquí está en la configuración de Prisma 7 para un servicio NestJS que se comunica con MySQL, no en un scaffold completo de Nest desde cero.

¿Cuáles son los cambios?

  • Prisma Client ya no incluye binarios nativos en Rust.
  • El camino del cliente se ha reescrito en TypeScript y funciona en entornos de ejecución normales de JS.
  • Los resultados generados por el cliente se encuentran en la fuente del proyecto, y no solo dentro de node_modules.
  • La regeneración del cliente ya no requiere reiniciar el servidor de desarrollo.
  • Aparece un nuevo archivo de configuración de Prisma.
  • Cada base de datos necesita un adaptador de controlador.
  • El cliente generado es independiente de la base de datos: se enfoca en la estructura del esquema, no en un binario de motor incorporado.
  • Prisma Studio se ejecuta mediante npx prisma studio.
  • Se admiten enum mapeados.
    1. Instale los paquetes de Prisma 7:
    npm install @prisma/client@7
    npm install -D prisma@7
    

    Prisma 7 no carga automáticamente las variables de entorno. Añada dotenv:

    npm install dotenv
    

    Ejemplos de versiones de Node y npm utilizadas en las notas iniciales de configuración:

    node -v
    v24.11.1
    npm -v
    11.6.2
    
    1. Cree la estructura inicial de Prisma:
    npx prisma init
    

    Eso crea un directorio prisma que contiene:

    • schema.prisma — conexión y modelos
    • prisma.config.ts — configuración
    • .env — generalmente credenciales de la base de datos
    1. Instale un adaptador de MySQL/MariaDB (los adaptadores se tratan nuevamente al final):
     npm install @prisma/adapter-mariadb
    
    1. Configure la URL, la ubicación del esquema, la salida de las migraciones y los datos iniciales. La documentación espera que prisma.config.ts se encuentre en la raíz del proyecto junto a 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 error común es PrismaConfigEnvError: Variable de entorno requerida faltante: DATABASE_URL, o quejas sobre la necesidad de una fuente de datos para prisma db push. Una discusión relacionada se encuentra en prisma/prisma#28590.

    1. Establezca la salida del cliente y defina los modelos en el esquema:
    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. Abrigue al cliente en un servicio de NestJS que se encargue de las operaciones de conexión/desconexión:
    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. Exportéelo desde un módulo global:
    import { Module, Global } from '@nestjs/common';
    import { PrismaService } from './prisma.service';
    
    @Global()
    @Module({
      providers: [PrismaService],
      exports: [PrismaService],
    })
    export class PrismaModule {}
    
    1. Script de semilla opcional para datos de prueba:
    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. Importar PrismaModule al módulo raíz:
    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 {}
    

    Con la base de datos en ejecución:

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

    Ignorar la salida generada en git:

    /src/generated
    

    Ejemplo de estructura de carpetas:

    └── 📁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
    

    Navegar por los datos localmente:

    npx prisma studio
    

    Adaptadores de controlador

    La versión anterior del Prisma Client dependía de un motor de consultas en Rust que convertía las solicitudes del cliente en SQL y establecía conexiones TCP mediante controladores integrados. Prisma 7 traslada la compilación a un compilador de consultas en JavaScript y elimina esos controladores incorporados. Los controladores de base de datos en JavaScript se comunican con la base de datos; los adaptadores de controlador realizan la traducción entre el compilador y dichos controladores. Para MySQL/MariaDB, utilice el adaptador mariadb. Consulte la sección de documentación de Prisma sobre adaptadores de controlador de base de datos para conocer la matriz actual.

    NestJS se beneficia al contar con una única instancia de cliente compartida por proceso. Crear un nuevo PrismaClient en cada manejador de solicitudes multiplica las conexiones y dificulta el razonamiento sobre las transacciones. El patrón de módulo global mencionado anteriormente mantiene un servicio visible para los módulos de funcionalidades, al tiempo que permite a las pruebas reemplazar PrismaService por uno falso.

    Al regenerar después de editar el esquema, confirme que la ruta output siga coincidiendo con la importación utilizada en prisma.service.ts. Una discrepancia entre la salida del generador y las rutas de importación es una causa común de errores “no se puede encontrar módulo” tras ejecuciones exitosas de prisma generate. Mantenga moduleFormat alineado con la forma en que Nest compila: las discrepancias entre CommonJS y ESM se manifiestan como errores sutiles en tiempo de ejecución en lugar de fallos claros durante la compilación.

    Eso es suficiente para que Prisma 7 se comunique con MySQL desde NestJS mediante adaptadores, archivos de configuración y un cliente generado, todo dentro de los límites del control de versiones.

    Lecturas relacionadas