Prisma для TypeScript: полное руководство с примерами

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Введение в Prisma: современный ORM для TypeScript

Prisma — это современный ORM (Object-Relational Mapping) для TypeScript и Node.js, который кардинально меняет подход к работе с базами данных. В отличие от традиционных ORM, таких как Sequelize или TypeORM, Prisma предлагает декларативную модель данных, автоматическую генерацию типов и интуитивно понятный API. Библиотека поддерживает PostgreSQL, MySQL, SQLite, SQL Server, MongoDB и CockroachDB.

Основная цель Prisma — сделать работу с базами данных безопасной, производительной и удобной. Благодаря интеграции с TypeScript, вы получаете автодополнение и проверку типов на уровне компиляции, что значительно снижает количество runtime-ошибок. Prisma состоит из трех ключевых компонентов:

  • Prisma Client — автоматически сгенерированный клиент для работы с БД
  • Prisma Migrate — система управления миграциями
  • Prisma Studio — GUI для просмотра и редактирования данных

Установка Prisma

Установка Prisma в проект на TypeScript выполняется через npm. Для начала создайте новый проект:

mkdir my-prisma-project
cd my-prisma-project
npm init -y

Установите Prisma CLI и Prisma Client:

npm install prisma @prisma/client --save

Инициализируйте Prisma в проекте:

npx prisma init

Эта команда создаст директорию prisma с файлом schema.prisma и файл .env для переменных окружения.

Быстрый старт: пример кода

Рассмотрим создание простого приложения для управления пользователями. Сначала определим модель в prisma/schema.prisma:

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

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

model User {
  id        Int      @id @default(autoincrement())
  email     String   @unique
  name      String?
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String?
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

Выполните миграцию для создания таблиц в SQLite:

npx prisma migrate dev --name init

Теперь создадим файл index.ts с примером использования:

import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

async function main() {
  // Создание пользователя
  const user = await prisma.user.create({
    data: {
      email: 'alice@example.com',
      name: 'Alice',
      posts: {
        create: { title: 'Hello World' }
      }
    }
  })
  console.log('Created user:', user)

  // Получение всех пользователей с их постами
  const users = await prisma.user.findMany({
    include: { posts: true }
  })
  console.log('All users:', JSON.stringify(users, null, 2))
}

main()
  .catch(e => console.error(e))
  .finally(async () => await prisma.$disconnect())

Запустите код:

npx ts-node index.ts

Основные методы Prisma Client

1. findUnique

Что делает: Находит единственную запись по уникальному идентификатору (id, email и т.д.).

Параметры:

  • where — объект с условиями поиска (обязательно)
  • include — (опционально) для включения связанных моделей
  • select — (опционально) для выбора конкретных полей

Пример:

const user = await prisma.user.findUnique({
  where: { email: 'alice@example.com' },
  include: { posts: true }
})

2. findFirst

Что делает: Находит первую запись, соответствующую условиям. Полезно, когда нужно найти запись по не уникальному полю.

Параметры:

  • where — объект с условиями
  • orderBy — сортировка
  • include, select — как в findUnique

Пример:

const firstPost = await prisma.post.findFirst({
  where: { published: true },
  orderBy: { createdAt: 'desc' }
})

3. findMany

Что делает: Возвращает массив записей, соответствующих условиям. Это основной метод для получения списка данных.

Параметры:

  • where — условия фильтрации
  • orderBy — сортировка
  • skip — количество пропускаемых записей (для пагинации)
  • take — количество возвращаемых записей
  • include, select

Пример:

const recentPosts = await prisma.post.findMany({
  where: { published: true },
  orderBy: { createdAt: 'desc' },
  take: 10,
  skip: 0,
  include: { author: true }
})

4. create

Что делает: Создает новую запись в базе данных.

Параметры:

  • data — объект с данными для создания (обязательно)
  • include — для включения связанных данных в результат

Пример:

const newUser = await prisma.user.create({
  data: {
    email: 'bob@example.com',
    name: 'Bob',
    posts: {
      create: [
        { title: 'Post 1', content: 'Content 1' },
        { title: 'Post 2', content: 'Content 2' }
      ]
    }
  },
  include: { posts: true }
})

5. update

Что делает: Обновляет существующую запись.

Параметры:

  • where — условие для поиска записи
  • data — объект с новыми данными

Пример:

const updatedUser = await prisma.user.update({
  where: { email: 'alice@example.com' },
  data: { name: 'Alice Johnson' }
})

6. upsert

Что делает: Комбинация create и update. Если запись существует — обновляет, если нет — создает новую.

Параметры:

  • where — условие для поиска
  • update — данные для обновления
  • create — данные для создания

Пример:

const upsertedUser = await prisma.user.upsert({
  where: { email: 'charlie@example.com' },
  update: { name: 'Charlie Updated' },
  create: { email: 'charlie@example.com', name: 'Charlie New' }
})

7. delete

Что делает: Удаляет запись из базы данных.

Параметры:

  • where — условие для поиска удаляемой записи

Пример:

const deletedUser = await prisma.user.delete({
  where: { id: 1 }
})

8. deleteMany

Что делает: Удаляет несколько записей, соответствующих условию.

Параметры:

  • where — условие для фильтрации записей

Пример:

const deletedCount = await prisma.post.deleteMany({
  where: { published: false }
})
console.log(`Deleted ${deletedCount.count} posts`)

9. count

Что делает: Возвращает количество записей, соответствующих условию.

Параметры:

  • where — (опционально) условие фильтрации

Пример:

const publishedPostsCount = await prisma.post.count({
  where: { published: true }
})
console.log(`Published posts: ${publishedPostsCount}`)

10. aggregate

Что делает: Выполняет агрегатные функции (sum, avg, min, max, count) над полями.

Параметры:

  • where — условие фильтрации
  • _count, _sum, _avg, _min, _max — объекты с полями для агрегации

Пример:

const stats = await prisma.post.aggregate({
  _count: { id: true },
  _avg: { id: true },
  where: { published: true }
})
console.log(`Total posts: ${stats._count.id}, Avg ID: ${stats._avg.id}`)

Реальный практический пример: API для блога

Создадим полноценный REST API для блога с использованием Express и Prisma. Начнем с установки дополнительных зависимостей:

npm install express cors
npm install -D @types/express @types/cors ts-node-dev

Создадим файл src/index.ts:

import express from 'express'
import cors from 'cors'
import { PrismaClient } from '@prisma/client'

const app = express()
const prisma = new PrismaClient()

app.use(cors())
app.use(express.json())

// Получение всех постов с авторами
app.get('/posts', async (req, res) => {
  try {
    const posts = await prisma.post.findMany({
      include: { author: { select: { name: true, email: true } } },
      orderBy: { createdAt: 'desc' }
    })
    res.json(posts)
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch posts' })
  }
})

// Создание поста
app.post('/posts', async (req, res) => {
  const { title, content, authorEmail } = req.body
  
  try {
    const post = await prisma.post.create({
      data: {
        title,
        content,
        author: {
          connect: { email: authorEmail }
        }
      },
      include: { author: true }
    })
    res.status(201).json(post)
  } catch (error) {
    res.status(400).json({ error: 'Failed to create post' })
  }
})

// Обновление поста
app.put('/posts/:id', async (req, res) => {
  const { id } = req.params
  const { title, content, published } = req.body
  
  try {
    const post = await prisma.post.update({
      where: { id: Number(id) },
      data: { title, content, published }
    })
    res.json(post)
  } catch (error) {
    res.status(400).json({ error: 'Failed to update post' })
  }
})

// Удаление поста
app.delete('/posts/:id', async (req, res) => {
  const { id } = req.params
  
  try {
    await prisma.post.delete({ where: { id: Number(id) } })
    res.status(204).send()
  } catch (error) {
    res.status(400).json({ error: 'Failed to delete post' })
  }
})

// Статистика блога
app.get('/stats', async (req, res) => {
  try {
    const [totalPosts, publishedPosts, usersCount] = await Promise.all([
      prisma.post.count(),
      prisma.post.count({ where: { published: true } }),
      prisma.user.count()
    ])
    
    res.json({
      totalPosts,
      publishedPosts,
      draftPosts: totalPosts -                    

Рекомендаций