EMZETT.
Увійти

Drizzle ORM

Коротко: Бібліотека TypeScript, що дає змогу визначати таблиці бази даних як код (замість чистого SQL) і автоматично створювати/оновлювати за ними відповідну схему бази даних.

Докладніше: Таблиці оголошуються у файлі схеми (наприклад, db/schema.ts) через pgTable(...). npx drizzle-kit push порівнює це визначення з реальною базою даних і приводить її у відповідність. drizzle.config.ts повідомляє Drizzle, де розташовані схема й база даних.

Наш контекст: Зміни схеми (наприклад, нові стовпці для завантажень програм) спершу перевірялися лише локально через drizzle-kit push — що одного разу призвело до того, що бойова база даних за ними не пішла, а сторінка адміністратора впала. Відтоді кожна зміна схеми супроводжується ще й файлом SQL-міграції.

Подробиці

push і generate/migrate

Drizzle розрізняє два легко сплутувані процеси: drizzle-kit push синхронізує схему напряму й «наживо» з базою даних (швидко, але без простежуваної історії — зручно для локальної розробки та швидкого прототипування), тоді як drizzle-kit generate створює справжній версіонований файл SQL-міграції, який ви комітите й контрольовано виконуєте в кожному середовищі (staging, продакшн) через drizzle-kit migrate. Лише другий підхід залишає в репозиторії простежувану історію всіх змін схеми — кожен файл міграції — самостійний файл .sql з порядковим номером, що точно показує, які оператори ALTER TABLE/CREATE TABLE і коли виконувалися. Це важливо й з погляду відповідності вимогам/аудиту: за push немає запису про те, КОЛИ та як змінювалася схема, за generate+migrate вона є.

Визначення схеми

Проста схема таблиці виглядає, наприклад, так:

export const users = pgTable("users", {
  id: uuid("id").primaryKey().defaultRandom(),
  email: text("email").notNull().unique(),
  createdAt: timestamp("created_at").defaultNow(),
});
export const posts = pgTable("posts", {
  id: uuid("id").primaryKey().defaultRandom(),
  authorId: uuid("author_id").references(() => users.id, { onDelete: "cascade" }),
  title: text("title").notNull(),
});
// Зв’язки для типобезпечних запитів JOIN (API реляційних запитів)
export const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));

Конструкція relations() призначена виключно для виведення типів TypeScript та API реляційних запитів (db.query.posts.findMany({ with: { author: true } })) — вона НЕ створює жодних обмежень зовнішнього ключа в самій базі даних; це робить лише .references() у визначенні таблиці.

Відмінність від Prisma і чистого SQL

Побудовник запитів навмисно близький до справжнього SQL (на відміну від більш сильно абстрагованих ORM на кшталт Prisma, що використовує власну мову запитів і окремий крок генерації коду) — db.select().from(users).where(eq(users.email, "...")) читається майже як сам SQL-запит, що полегшує налагодження, бо легше простежити, який SQL зрештою виконується (Drizzle також пропонує .toSQL(), що виводить згенерований запит разом із параметрами). Prisma ж постачає зріліший візуальний інтерфейс адміністрування Prisma Studio, тоді як аналог Drizzle (Drizzle Studio) простіший. Практична різниця в повсякденній роботі: у Drizzle немає власного кроку генерації коду під час збірки (схема вже Є звичайним кодом TypeScript), тоді як Prisma після кожної зміни схеми потребує prisma generate, щоб перестворити типобезпечний клієнт — це зазвичай робить цикл розробки з Drizzle швидшим за частих змін схеми.

Типові підводні камені

Часта помилка — використовувати push у продакшні, хоча він призначений насамперед для локальної розробки: без історії міграцій є ризик, що за складніших змін (наприклад, перейменування стовпця) push витлумачить зміну як «видалити стовпець + створити новий» і втратить наявні дані в цьому стовпці замість перейменування. drizzle-kit generate розпізнає такі перейменування інтерактивно й прямо питає, це перейменування чи справжнє видалення+створення.

Див. також: Neon