Node.jsМодуль 5: Базы данных
PostgreSQL и Prisma
Работа с PostgreSQL через Prisma ORM
Цель урока
В этом уроке ты научишься:
- Настраивать Prisma
- Создавать схемы и миграции
- Выполнять типизированные запросы
Установка
npm install prisma @prisma/client
npx prisma initСхема Prisma
// prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
password String
role Role @default(USER)
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
tags Tag[]
createdAt DateTime @default(now())
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
}
enum Role {
USER
ADMIN
}Миграции
# Создать миграцию
npx prisma migrate dev --name init
# Применить миграции в production
npx prisma migrate deploy
# Сбросить базу данных
npx prisma migrate reset
# Синхронизация без миграции (dev)
npx prisma db pushПодключение
// lib/prisma.js
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient({
log: ['query', 'info', 'warn', 'error']
});
module.exports = prisma;CRUD операции
Create
const prisma = require('./lib/prisma');
// Создание
const user = await prisma.user.create({
data: {
email: 'ivan@example.com',
name: 'Иван',
password: 'hashedpassword'
}
});
// С связями
const post = await prisma.post.create({
data: {
title: 'Мой пост',
content: 'Контент',
author: {
connect: { id: 1 }
},
tags: {
connectOrCreate: [
{ where: { name: 'JavaScript' }, create: { name: 'JavaScript' } }
]
}
}
});
// Множественное создание
await prisma.user.createMany({
data: [
{ email: 'a@example.com', name: 'A' },
{ email: 'b@example.com', name: 'B' }
]
});Read
// Все записи
const users = await prisma.user.findMany();
// С фильтром
const users = await prisma.user.findMany({
where: {
role: 'ADMIN',
email: { contains: 'example.com' }
}
});
// Одна запись
const user = await prisma.user.findUnique({
where: { id: 1 }
});
const user = await prisma.user.findFirst({
where: { email: { contains: 'ivan' } }
});
// С связями
const user = await prisma.user.findUnique({
where: { id: 1 },
include: {
posts: true
}
});
// Выбор полей
const users = await prisma.user.findMany({
select: {
id: true,
name: true,
email: true
}
});
// Сортировка и пагинация
const posts = await prisma.post.findMany({
orderBy: { createdAt: 'desc' },
skip: 10,
take: 10
});Update
// Обновление
const user = await prisma.user.update({
where: { id: 1 },
data: { name: 'Новое имя' }
});
// Множественное обновление
await prisma.user.updateMany({
where: { role: 'USER' },
data: { role: 'ADMIN' }
});
// Upsert
const user = await prisma.user.upsert({
where: { email: 'ivan@example.com' },
update: { name: 'Иван' },
create: { email: 'ivan@example.com', name: 'Иван' }
});Delete
// Удаление
await prisma.user.delete({
where: { id: 1 }
});
// Множественное удаление
await prisma.user.deleteMany({
where: { role: 'INACTIVE' }
});Фильтры
const users = await prisma.user.findMany({
where: {
// Равенство
role: 'ADMIN',
// Сравнение
id: { gt: 10 }, // >
id: { gte: 10 }, // >=
id: { lt: 100 }, // <
id: { lte: 100 }, // <=
// Строки
email: { contains: 'example' },
email: { startsWith: 'ivan' },
email: { endsWith: '.com' },
// Логические
AND: [{ role: 'USER' }, { name: { not: null } }],
OR: [{ role: 'ADMIN' }, { role: 'MODERATOR' }],
NOT: { email: { contains: 'test' } },
// Связи
posts: {
some: { published: true }
}
}
});Транзакции
// Автоматическая транзакция
const [user, post] = await prisma.$transaction([
prisma.user.create({ data: { email: 'a@example.com' } }),
prisma.post.create({ data: { title: 'Пост', authorId: 1 } })
]);
// Интерактивная транзакция
await prisma.$transaction(async (tx) => {
const user = await tx.user.create({
data: { email: 'ivan@example.com' }
});
await tx.post.create({
data: { title: 'Пост', authorId: user.id }
});
});Практика
Задание: API с Prisma
Задача: Создай CRUD для пользователей.
Решение:
const express = require('express');
const prisma = require('./lib/prisma');
const app = express();
app.use(express.json());
app.get('/users', async (req, res) => {
const users = await prisma.user.findMany({
select: { id: true, name: true, email: true }
});
res.json(users);
});
app.post('/users', async (req, res) => {
const user = await prisma.user.create({
data: req.body
});
res.status(201).json(user);
});
app.put('/users/:id', async (req, res) => {
const user = await prisma.user.update({
where: { id: parseInt(req.params.id) },
data: req.body
});
res.json(user);
});
app.delete('/users/:id', async (req, res) => {
await prisma.user.delete({
where: { id: parseInt(req.params.id) }
});
res.status(204).send();
});Проверь себя
- Как создать миграцию?
- Что делает
include? - Как выполнить транзакцию?