Skip to main content

Prisma

Как устроен доступ к базе данных в @lowcode/api и как Prisma встроена в архитектуру платформы.

🎯 Зачем эта страница

Задача этой страницы — объяснить:

  • что такое Prisma и какие задачи она решает;
  • как описывается схема БД и откуда берётся Prisma Client;
  • как Prisma интегрирована в NestJS-модуль @lowcode/api;
  • как правильно использовать Prisma в сервисах и где находятся ключевые файлы.

1. Что такое Prisma

Prisma — это ORM следующего поколения для TypeScript/Node.js. Она состоит из трёх частей:

  1. Prisma Schema — декларативное описание моделей БД в файле schema.prisma.
  2. Prisma Migrate — система миграций, которая поддерживает схему БД в актуальном состоянии.
  3. 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/*Изменения схемы во времени
PrismaServiceapps/api/src/database/prisma.service.tsОбёртка над PrismaClient
PrismaModuleapps/api/src/database/prisma.module.tsГлобальный модуль с Prisma
Использование в APIapps/api/src/**/**.service.tsЗапросы к БД через PrismaService

8. Что нужно знать разработчику

Минимальный набор знаний, чтобы уверенно работать с Prisma в проекте:

  1. Где лежит schema.prisma и как там описываются модели.
  2. Как запускать миграции в dev/CI/Docker-окружениях.
  3. Как устроен PrismaService и как он инжектится в сервисы.
  4. Как писать типичные запросы (findMany, findUnique, create, update, delete).

Этого достаточно, чтобы:

  • добавлять новые таблицы и связи в БД;
  • расширять API новыми сущностями;
  • понимать, как данные проходят путь от HTTP-запроса до PostgreSQL и обратно.