Prisma
Как устроен доступ к базе данных в @lowcode/api и как Prisma встроена в архитектуру платформы.
🎯 Зачем эта страница
Задача этой страницы — объяснить:
- что такое Prisma и какие задачи она решает;
- как описывается схема БД и откуда берётся Prisma Client;
- как Prisma интегрирована в NestJS-модуль
@lowcode/api; - как правильно использовать Prisma в сервисах и где находятся ключевые файлы.
1. Что такое Prisma
Prisma — это ORM следующего поколения для TypeScript/Node.js. Она состоит из трёх частей:
- Prisma Schema — декларативное описание моделей БД в файле
schema.prisma. - Prisma Migrate — система миграций, которая поддерживает схему БД в актуальном состоянии.
- Prisma Client — сгенерированный type-safe клиент для запросов к базе.
Основные преимущества:
- строгая типизация: типы моделей и запросов генерируются из
schema.prisma; - одна точка правды — схема БД описана в одном месте и синхронизирована с кодом;
- удобные запросы: нет необходимости писать SQL в большинстве типичных случаев.
2. Минимальный пример Prisma в отрыве от проекта
2.1. Схема schema.prisma
// schema.prisma
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
generator client {
provider = "prisma-client-js"
}
model Project {
id String @id @default(cuid())
name String
createdAt DateTime @default(now())
}
2.2. Генерация клиента
npx prisma generate
После этого появляется сгенерированный клиент, который можно использовать в коде.
2.3. Использование клиента
import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
async function main() {
const projects = await prisma.project.findMany();
console.log(projects);
}
main().finally(() => prisma.$disconnect());
Этот пример показывает базовый цикл работы: схема → генерация клиента → запросы.
3. Где Prisma используется в @lowcode/api
В lowcode-платформе Prisma отвечает за доступ к PostgreSQL для бэкенда @lowcode/api.
Ключевые места:
- файл схемы:
apps/api/prisma/schema.prisma; - миграции:
apps/api/prisma/migrations/*; - обёртка над клиентом:
PrismaServiceвнутри NestJS-модуля (обычно вapps/api/src/database/prisma.service.tsили аналогичном пути); - использование в сервисах:
apps/api/src/**/**.service.ts.
Архитектурно это выглядит так:
Контроллер → Сервис → PrismaService → PostgreSQL
Контроллеры не работают с Prisma напрямую; они обращаются к сервисам, а те используют общий PrismaService.
4. Интеграция Prisma с NestJS
4.1. PrismaService
В проекте используется типичный паттерн обёртки над PrismaClient.
Упрощённый пример:
// apps/api/src/database/prisma.service.ts
import { INestApplication, Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';
@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
async onModuleInit() {
await this.$connect();
}
async enableShutdownHooks(app: INestApplication) {
this.$on('beforeExit', async () => {
await app.close();
});
}
}
Этот сервис:
- наследуется от
PrismaClient; - подключается к базе при инициализации модуля;
- аккуратно закрывает соединения при остановке приложения.
4.2. PrismaModule
Обычно создаётся отдельный модуль, который экспортирует PrismaService:
// apps/api/src/database/prisma.module.ts
import { Global, Module } from '@nestjs/common';
import { PrismaService } from './prisma.service';
@Global()
@Module({
providers: [PrismaService],
exports: [PrismaService],
})
export class PrismaModule {}
@Global() делает модуль доступным во всём приложении без явного импорта в каждый модуль.
4.3. Подключение к AppModule
В apps/api/src/app.module.ts модуль БД импортируется один раз:
@Module({
imports: [PrismaModule /* другие модули */],
})
export class AppModule {}
После этого любой сервис может получать PrismaService через DI.
5. Как сервисы используют Prisma
Пример сервиса для работы с проектами:
// apps/api/src/projects/projects.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../database/prisma.service';
@Injectable()
export class ProjectsService {
constructor(private readonly prisma: PrismaService) {}
findAll() {
return this.prisma.project.findMany();
}
findOne(id: string) {
return this.prisma.project.findUnique({ where: { id } });
}
create(data: { name: string }) {
return this.prisma.project.create({ data });
}
}
Особенности подхода:
- Сервис получает
PrismaServiceчерез конструктор. - Вся работа с БД сосредоточена в сервисах (контроллеры только прокидывают DTO).
- Типы моделей (
project,projectVersionи т.п.) генерируются автоматически изschema.prisma.
6. Миграции и окружения
Prisma Migrate используется для синхронизации схемы БД с кодом.
6.1. Локальные миграции
В dev-режиме (локально):
cd apps/api
pnpm prisma:migrate-dev
(конкретная команда может отличаться в зависимости от package.json, но общий смысл такой).
6.2. Миграции в Docker-окружении
В Docker-композе для разработки и e2e-тестов включён шаг запуска миграций при старте контейнера API. Это гарантирует, что при поднятии окружения схема БД будет актуальной.
Таким образом:
- локальная разработка и тесты используют одни и те же миграции;
- состояние схемы контролируется и версионируется в Git.
7. Где искать код, связанный с Prisma
| Компонент | Путь | Описание |
|---|---|---|
| Схема БД | apps/api/prisma/schema.prisma | Описание моделей БД |
| Миграции | apps/api/prisma/migrations/* | Изменения схемы во времени |
| PrismaService | apps/api/src/database/prisma.service.ts | Обёртка над PrismaClient |
| PrismaModule | apps/api/src/database/prisma.module.ts | Глобальный модуль с Prisma |
| Использование в API | apps/api/src/**/**.service.ts | Запросы к БД через PrismaService |
8. Что нужно знать разработчику
Минимальный набор знаний, чтобы уверенно работать с Prisma в проекте:
- Где лежит
schema.prismaи как там описываются модели. - Как запускать миграции в dev/CI/Docker-окружениях.
- Как устроен
PrismaServiceи как он инжектится в сервисы. - Как писать типичные запросы (
findMany,findUnique,create,update,delete).
Этого достаточно, чтобы:
- добавлять новые таблицы и связи в БД;
- расширять API новыми сущностями;
- понимать, как данные проходят путь от HTTP-запроса до PostgreSQL и обратно.