PrismaJuniorTechnical

Как структурирована схема Prisma (schema.prisma)? Что такое модели, поля и связи (relations)?

schema.prisma состоит из трёх блоков: datasource (подключение к БД), generator (настройка кодогенерации) и model (описание таблиц с полями, типами и атрибутами). Поля-связи виртуальные — реальные колонки FK создаются через @relation.

Структура файла schema.prisma

Файл schema.prisma — единственный источник истины о структуре БД и настройках Prisma. Он состоит из трёх блоков: datasource, generator и model.

datasource — подключение к базе данных

datasource db {
  provider = "postgresql" // postgresql | mysql | sqlite | sqlserver | mongodb | cockroachdb
  url      = env("DATABASE_URL") // строка подключения из переменной окружения
}

Значение DATABASE_URL обычно хранится в файле .env и имеет формат: postgresql://user:password@localhost:5432/dbname.

generator — настройка генерации клиента

generator client {
  provider        = "prisma-client-js"
  // опционально: выходная директория клиента
  output          = "../src/generated/prisma"
  // опционально: preview-фичи
  previewFeatures = ["fullTextSearch", "metrics"]
}

После изменения схемы нужно запустить npx prisma generate, чтобы пересоздать типизированный клиент.

model — описание таблиц

Каждая модель соответствует таблице в БД. Поля объявляются в формате: имя Тип атрибуты:

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?             // опциональное поле (NULL в БД)
  role      Role     @default(USER) // enum с дефолтом
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  posts     Post[]              // виртуальное поле-связь

  @@index([email])              // индекс на уровне таблицы
  @@map("users")                // настоящее имя таблицы в БД
}

Типы полей

  • Скалярные: String, Int, Float, Boolean, DateTime, Json, Bytes, BigInt, Decimal
  • Модели-связи: ссылки на другие модели (Post[], User?)
  • Перечисления: enum Role { USER ADMIN }

Атрибуты полей

model Post {
  id        Int      @id @default(autoincrement()) // первичный ключ, автоинкремент
  uuid      String   @default(uuid())              // UUID по умолчанию
  cuid      String   @default(cuid())              // CUID по умолчанию
  title     String   @db.VarChar(255)              // нативный SQL-тип
  content   String?  @db.Text
  published Boolean  @default(false)
  authorId  Int
  author    User     @relation(fields: [authorId], references: [id], onDelete: Cascade)
}

Enum

enum Role {
  USER
  ADMIN
  MODERATOR
}

Атрибуты уровня модели

model UserProfile {
  userId   Int
  tenantId Int
  data     String

  @@id([userId, tenantId])               // составной первичный ключ
  @@unique([userId, tenantId])           // составной уникальный ключ
  @@index([tenantId])                    // индекс
  @@map("user_profiles")                 // имя таблицы в БД
}

Полный рабочий пример

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

enum Status {
  DRAFT
  PUBLISHED
  ARCHIVED
}

model Author {
  id    Int    @id @default(autoincrement())
  name  String
  posts Post[]
}

model Post {
  id       Int      @id @default(autoincrement())
  title    String
  status   Status   @default(DRAFT)
  authorId Int
  author   Author   @relation(fields: [authorId], references: [id])

  @@index([status, authorId])
}

Подводные камни

  • Поля-связи (например, posts Post[]) — виртуальные: они не создают колонок в БД, а используются только в Prisma Client для навигации. Реальная колонка всегда на стороне с @relation(fields: [...]).
  • Тип Json в PostgreSQL хранится как jsonb, но фильтрация по вложенным ключам JSON в Prisma ограничена. Сложные JSON-запросы лучше выполнять через $queryRaw.
  • @db.VarChar(255) и другие нативные аннотации зависят от СУБД — они нарушают переносимость схемы между PostgreSQL и MySQL.
  • Переименование модели или поля без @@map/@map приведёт к DROP + CREATE таблицы/колонки в миграции, а не к RENAME — это потеря данных.
  • Enum в PostgreSQL создаётся как отдельный тип. Добавление нового значения в enum — не обратимо совместимая операция в старых версиях PostgreSQL (до 12).
  • @updatedAt управляется Prisma на уровне приложения, а не триггером БД. Если запись обновить обходя Prisma (прямым SQL), поле не обновится.
  • Файл schema.prisma не поддерживает импорты из других файлов — вся схема должна быть в одном файле (или использовать preview-фичу prismaSchemaFolder).

Common mistakes

  • Путает Prisma Client API с гарантиями базы данных: индексы, блокировки и isolation level не создаются магически.
  • Не объясняет, где в lifecycle находится schema.prisma, models, fields и relations.
  • Не разделяет validation, authorization, business logic и persistence.
  • Игнорирует ошибки, лимиты входных данных, observability и тестирование.

What the interviewer is testing

  • Может объяснить schema.prisma, models, fields и relations на примере кода.
  • Называет ключевые API: model, @id, @relation.
  • Отделяет ORM/query builder поведение от реального поведения СУБД.
  • Видит production-риски: безопасность, отказоустойчивость, логирование и тесты.

Sources

Related topics