webroad.online
  1. 1Веб
  2. 2HTML
  3. 3CSS
  4. 4JavaScript
  5. 5TypeScript
  6. 6Git
  7. 7Инструменты
  8. 8React
  9. 9Стейт-менеджмент
  10. 10Next.js
  11. 11Формы
  12. 12Данные и бэкенд
  13. 13SEO
  14. 14Tailwind CSS
  15. 15Анимации
  16. 16Тестирование
  17. 17Архитектура
Данные и бэкенд · Урок 3 из 4

ORM: Drizzle и Prisma

Схемы на TypeScript, типизированные запросы, миграции; чистый SQL, Drizzle или Prisma.

Обновлено

Что такое ORM

ORM (Object-Relational Mapper) позволяет работать с базой через код на TypeScript вместо SQL в виде текста. Вы один раз описываете таблицы как схему, а ORM даёт:

  • типизированные запросы — автодополнение по колонкам, ошибки при компиляции, если ошиблись в имени;
  • миграции — версионированную историю изменений структуры;
  • встроенную защиту от SQL-инъекций.

Способы доступа к базе

Вариант Пример Плюсы Минусы
чистый SQL (драйвер) sql`SELECT ...` с @neondatabase/serverless полный контроль, ноль абстракций нет автоматических типов, ручные миграции
конструктор запросов / ORM «как SQL» Drizzle, Kysely близко к SQL, типизировано, легко, работает на edge нужно знать SQL
классический ORM Prisma очень простой API, отличный инструментарий (Studio) толще абстракция, генерация клиента

Drizzle — схема и запросы

// shared/api/schema.ts
import { pgTable, serial, text, integer, timestamp } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  name: text('name').notNull(),
  email: text('email').notNull().unique(),
})

export const posts = pgTable('posts', {
  id: serial('id').primaryKey(),
  userId: integer('user_id').notNull().references(() => users.id),
  title: text('title').notNull(),
  createdAt: timestamp('created_at').defaultNow().notNull(),
})
import { drizzle } from 'drizzle-orm/neon-http'
import { desc, eq } from 'drizzle-orm'

const db = drizzle(process.env.DATABASE_URL!)

const latest = await db.select().from(posts).where(eq(posts.userId, 1)).orderBy(desc(posts.createdAt)).limit(10)
const [created] = await db.insert(posts).values({ userId: 1, title: 'Privet' }).returning()
type Post = typeof posts.$inferSelect                    // тип строки, из схемы

Обратите внимание: userId в коде, user_id в базе — сопоставление camelCase ↔ snake_case делает ORM.

Prisma — та же идея, другой стиль

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
}
const latest = await prisma.post.findMany({ where: { authorId: 1 }, orderBy: { id: 'desc' }, take: 10, include: { author: true } })

Миграции

Миграция — файл, описывающий изменение структуры (новая таблица, новая колонка), который применяется один раз, по порядку, к каждой базе (локальной, preview, продакшен).

npx drizzle-kit generate    # из TS-схемы → SQL-файл миграции
npx drizzle-kit migrate     # применяет миграции, которые ещё не выполнялись
Правило Почему
миграции хранятся в Git одинаковая история везде
уже применённую миграцию не правят создают новую
«разрушительные» изменения (переименование, удаление колонки) — по шагам существующие данные и старый код должны работать в промежутке

Где они лежат в FSD

Схема и клиент БД → shared/api/. Запросы сущности → entities/<x>/api/ (как entities/lesson/api/lesson-api.ts в проекте). Компоненты никогда не импортируют клиент БД напрямую.

Коротко

  • ORM = схема на TS → типизированные запросы + миграции + защита от инъекций.
  • Drizzle = близко к SQL, легко; Prisma = простой API, богатый инструментарий; чистый SQL = полный контроль.
  • Миграции версионируются в Git и применяются по порядку; после применения их не правят.

Официальные источники

Упражнения

Была ли страница полезной?

Один клик — без регистрации.