Drizzle ORM
Kısaca: Veri tabanı tablolarını düz SQL yerine kod olarak tanımlamana ve buna uyan veri tabanı şemasını otomatik üretip güncellemene olanak tanıyan bir TypeScript kütüphanesi.
Biraz daha ayrıntılı: Tablolar bir şema dosyasında (örneğin db/schema.ts) pgTable(...) ile tanımlanır. npx drizzle-kit push bu tanımı gerçek veri tabanıyla karşılaştırır ve eşitler. drizzle.config.ts, Drizzle’a şemanın ve veri tabanının nerede olduğunu söyler.
Bizim bağlamımız: Şema değişiklikleri (örneğin yazılım indirmeleri için yeni sütunlar) önce yalnızca yerelde drizzle-kit push ile denendi — bu bir keresinde üretim veri tabanının onu izlememesi ve yönetim sayfasının çökmesi anlamına geldi. O zamandan beri her şema değişikliği ayrıca bir SQL migrasyon dosyasıyla gelir.
Ayrıntılı
push ve generate/migrate
Drizzle, kolayca karıştırılan iki iş akışı ayırt eder: drizzle-kit push şemayı doğrudan ve canlı olarak veri tabanına eşitler (hızlı, ancak izlenebilir geçmiş olmadan — yerel geliştirme ve hızlı prototipleme için kullanışlı), drizzle-kit generate ise commit ettiğin ve drizzle-kit migrate ile her ortamda (staging, üretim) kontrollü biçimde çalıştırdığın gerçek, sürümlü bir SQL migrasyon dosyası üretir. Yalnızca ikinci yaklaşım, depoda tüm şema değişikliklerinin izlenebilir bir geçmişini bırakır — her migrasyon dosyası, hangi ALTER TABLE/CREATE TABLE ifadelerinin ne zaman çalıştırıldığını gösteren sıra numaralı bağımsız bir .sql dosyasıdır. Bu, uyumluluk/denetim açısından da önemlidir: push ile şemanın NE ZAMAN ve nasıl değiştiğine dair kayıt yoktur, generate+migrate ile vardır.
Şema tanımı
Basit bir tablo şeması örneğin şöyle görünür:
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(),
});
// Tür güvenli JOIN sorguları için ilişkiler (ilişkisel sorgu API'si)
export const postsRelations = relations(posts, ({ one }) => ({
author: one(users, { fields: [posts.authorId], references: [users.id] }),
}));relations() yapısı yalnızca TypeScript tür çıkarımı ve ilişkisel sorgu API’si (db.query.posts.findMany({ with: { author: true } })) içindir — veri tabanının kendisinde HİÇBİR yabancı anahtar kısıtlaması OLUŞTURMAZ; bunu yalnızca tablo tanımındaki .references() yapar.
Prisma ve ham SQL’den farkı
Sorgu oluşturucu bilinçli olarak gerçek SQL’e yakın tutulmuştur (kendi sorgu dilini ve ayrı bir kod üretim adımını kullanan Prisma gibi daha soyut ORM’lerin aksine) — db.select().from(users).where(eq(users.email, "...")) neredeyse SQL sorgusunun kendisi gibi okunur; bu hata ayıklamayı kolaylaştırır, çünkü sonunda hangi SQL’in çalıştığını izlemek daha kolaydır (Drizzle ayrıca üretilen sorguyu parametreleriyle birlikte yazdıran .toSQL() sunar). Prisma ise Prisma Studio ile daha olgun bir görsel yönetim arayüzü sunar, Drizzle’ın karşılığı (Drizzle Studio) daha yalındır. Günlük işte pratik bir fark: Drizzle’ın kendi kod üretim derleme adımı yoktur (şema zaten düz TypeScript kodudur), oysa Prisma tür güvenli istemciyi yeniden üretmek için her şema değişikliğinden sonra prisma generate gerektirir — bu, şema sık değiştiğinde Drizzle’ın geliştirme döngüsünü daha hızlı kılma eğilimindedir.
Sık tuzaklar
Sık yapılan bir hata, esas olarak yerel geliştirme için olmasına rağmen üretimde push kullanmaktır — migrasyon geçmişi olmadan, daha karmaşık değişikliklerde (örneğin bir sütunu yeniden adlandırma) push değişikliği “sütunu sil + yeni sütun oluştur” olarak yorumlayıp o sütundaki mevcut verileri yeniden adlandırmak yerine kaybetme riski vardır. drizzle-kit generate bu tür yeniden adlandırmaları etkileşimli olarak algılar ve bunun bir yeniden adlandırma mı yoksa gerçek bir sil+oluştur mu olduğunu açıkça sorar.
Ayrıca bak: Neon