Strona główna / Artykuły

Prisma 7 z adapterami sterowników NestJS i MySQL

Prisma 7 w globalnym module NestJS z MySQL: klient w TypeScript, plik prisma.config.ts oraz adapter sterownika MariaDB, tak skonfigurowane, że każda usługa korzysta z tego samego.

Wydawca: REACTAPP.TOP5 min czytania1112 słów

Źródła: Get Started With Prisma 7 with Nest Js & MySQL

Prisma to ORM dla Node.js i TypeScript, który zarządza schematami, relacjami oraz zapytaniami typowanymi. Prisma 7 zmienia strukturę czasu wykonywania: ścieżka klienta jest w niektórych aspektach prostsza, a w innych bardziej rygorystyczna. Tutaj skupiamy się na konfiguracji Prisma 7 dla usługi NestJS komunikującej się z MySQL – a nie na pełnym szablonie Nest od zera.

Jakie są zmiany?

  • Prisma Client nie zawiera już binarnych plików napisanych w języku Rust.
  • Ścieżka klienta została przepisana w języku TypeScript i działa w zwykłych środowiskach wykonywania JS.
  • Wytwarzane pliki klienta znajdują się w źródle projektu, a nie są ukryte wyłącznie w katalogu node_modules.
  • Przegenerowanie klienta nie wymaga już restartowania serwera rozwojowego.
  • Pojawił się nowy plik konfiguracyjny Prisma.
  • Każda baza danych wymaga adaptera sterownika.
  • Wygenerowany klient jest bez względu na bazę danych: liczy się dla niego struktura schematu, a nie wbudowany plik binarny silnika.
  • Prisma Studio uruchamia się za pomocą npx prisma studio.
  • Zapewniona jest obsługa mappowanych enum.
    1. Zainstaluj pakiety Prisma 7:
    npm install @prisma/client@7
    npm install -D prisma@7
    

    Prisma 7 nie ładowa automatycznie zmiennych środowiskowych. Dodaj plik dotenv:

    npm install dotenv
    

    Przykładowe wersje Node i npm użyte we wstępnych instrukcjach konfiguracji:

    node -v
    v24.11.1
    npm -v
    11.6.2
    
    1. Stwórz początkową strukturę Prisma:
    npx prisma init
    

    To tworzy katalog prisma, który zawiera:

    • schema.prisma — połączenie i modele
    • prisma.config.ts — konfiguracja
    • .env — zazwyczaj dane do logowania do bazy danych
    1. Zainstaluj adapter MySQL/MariaDB (adapterzy są ponownie omawiane na końcu):
     npm install @prisma/adapter-mariadb
    
    1. Konfiguruj adres URL, lokalizację schematu, pliki wyjściowe z migracji oraz dane początkowe. Dokumentacja wymaga pliku prisma.config.ts w korzeniu projektu obok 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!
      },
    });
    

    Częstym problemem jest błąd PrismaConfigEnvError: Brakuje wymaganej zmiennej środowiskowej: DATABASE_URL lub skargi na konieczność użycia źródła danych do wykonywania polecenia prisma db push. Jedna z omawianych tematów to prisma/prisma#28590.

    1. Ustaw wyjście klienta i zdefiniuj modele w schemacie:
    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. Otocz klienta usługą NestJS, która zarządza operacjami połączenia i rozłączenia:
    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. Eksportuj go z modułu globalnego:
    import { Module, Global } from '@nestjs/common';
    import { PrismaService } from './prisma.service';
    
    @Global()
    @Module({
      providers: [PrismaService],
      exports: [PrismaService],
    })
    export class PrismaModule {}
    
    1. Opcjonalny skrypt nasionowy do danych testowych:
    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. Importuj PrismaModule do modułu głównego:
    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 {}
    

    Gdy baza danych jest uruchomiona:

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

    Zignoruj wygenerowane pliki w git:

    /src/generated
    

    Przykładowa struktura folderów:

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

    Przeglądaj dane lokalnie:

    npx prisma studio
    

    Adaptatory sterowników

    Stary Prisma Client opierał się na silniku zapytań Rust, który przekształcał wywołania klienta w SQL i nawiązywał połączenia TCP za pomocą wbudowanych sterowników. Prisma 7 przenosi kompilację do kompilatora zapytań w JavaScript i usuwa te wbudowane sterowniki. Sterowniki bazy danych w JavaScript komunikują się z bazą danych; adaptery sterowników tłumaczą pomiędzy kompilatorem a tymi sterownikami. Dla MySQL/MariaDB należy użyć adaptera mariadb. Aktualną listę dostępnych adapterów znajdziesz w sekcji dokumentacji Prisma poświęconej adapterom sterowników bazy danych.

    W architekturze NestJS korzyść wynika z posiadania jednej wspólnej instancji klienta na proces. Tworzenie nowego obiektu PrismaClient w każdym obsługiwaczu żądań powoduje mnożenie się połączeń i utrudnia rozumienie transakcji. Powyższy wzorzec modułu globalnego utrzymuje jeden serwis widoczny dla modułów funkcjonalnych, jednocześnie umożliwiając testom zastąpienie PrismaService wersją symulowaną.

    Gdy regenerujesz projekt po edycji schematu, upewnij się, że ścieżka output nadal odpowiada ścieżce importu użytej w pliku prisma.service.ts. Niezgodność pomiędzy wynikiem generatora a ścieżkami importu jest częstą przyczyną błędów „cannot find module” po udanych wykonyaniach polecenia prisma generate. Utrzymuj moduleFormat zgodnie z sposobem kompilacji w NestJS – różnice między CommonJS a ESM objawiają się subtelnymi błędami w czasie wykonywania, a nie wyraźnymi błędami kompilacji.

    To wystarczy, aby Prisma 7 mogło komunikować się z MySQL za pośrednictwem NestJS przy użyciu adapterów, plików konfiguracyjnych oraz wygenerowanego klienta znajdujących się w granicach kontroli źródeł.

    Literatura pokrewna