Mundarija (30)
- Bu darsda
- 1. Nega bu kerak?
- 2. O'rnatish va sxema
- 2.1 Paketlar
- 2.2 pgTable: jadval TypeScript'da
- 2.3 Ulanish
- 3. O'qish: select
- 3.1 Asosiy shakl
- 3.2 select() — sxemadagi hamma ustun
- 3.3 Murakkab shart
- 3.4 JOIN
- 4. Agregatlar va sql template
- 4.1 sql va sql.raw
- 4.2 toSQL() — bajarmasdan ko'rish
- 5. Yozish: insert, update, delete
- 5.1 insert … returning
- 5.2 update va delete
- 5.3 Tuzoq: where siz update
- 5.4 Xatolar
- 6. Tip xulosasi
- 7. Drizzle, Prisma va pg — o'lchov
- 8. Ko'p uchraydigan xatolar
- 9. Mashqlar
- 1-mashq (oson): Drizzle funksiyalari
- 2-mashq (o'rta): debug uchun SQL'ni "to'ldirish"
- 3-mashq (qiyin): filtr va son bitta shart bilan
- 10. Loyiha qadami: kanon tajribasi, loyihaga kirmaydi
- 11. Real ishda
- Xulosa
- Manbalar
Drizzle ORM: pgTable sxemasi, select/insert/update va tip xulosasi
Qisqacha: Drizzle — "SQL'ga o'xshagan TypeScript": sxema
.tsfayldapgTable(...)bilan yoziladi, so'rov esa SQL tartibida quriladi —db.select().from(vazifalar).where(eq(vazifalar.egasiId, 2)). Kod generatsiyasi yo'q: turlar sxemadan to'g'ridan chiqadi (typeof vazifalar.$inferSelect). Paket kichik (kanon: 16 MB, bog'liqliksiz), so'rov tezligipgga yaqin (ro'yxat 1.08 ms vs 1.00 ms). Tuzoq:updateniwheresiz yozsangiz — xato yo'q, biz sinadik: 50 qatorning hammasi o'zgardi.
Bu darsda
- Mavjud bazaga Drizzle sxemasini
pgTablebilan yozasiz. select,insert,update,deleteso'rovlarini quruvchi bilan yozasiz va SQL'ini o'qiysiz.eq,and,or,ilike,inArray,isNullvasqltemplate'ni ishlatasiz.$inferSelect/$inferInsertturlarini va TypeScript xatolarini o'qiysiz.- Drizzle'ni Prisma va raw
pgbilan o'lchov bo'yicha solishtirasiz.
Oldin bilishingiz kerak: ORM, query builder va raw SQL, Prisma prodakshnda, node-postgres (pg) asoslari, Generics: turni parametr qilish.
1. Nega bu kerak?
Oldingi to'qqiz darsda Prisma'ni o'rgandik — kursning asosiy ORM'i. Lekin uning narxini ham ko'rdik: alohida sxema tili (schema.prisma), kod generatsiyasi (prisma generate), 72 MB klient, ba'zi SQL imkoniyatlari uchun raw SQL (ORM, query builder va raw SQL darsidagi taqqoslash).
Drizzle boshqa falsafa bilan qurilgan: "SQL'ni bilsangiz — Drizzle'ni bilasiz". Sxema — oddiy TypeScript fayl. So'rov — SQL so'zlari tartibida (select … from … where … orderBy … limit). Natija turi — TypeScript'ning o'z tip xulosasi (type inference) bilan, generatsiyasiz.
O'xshatish: Prisma — avtomat korobkali mashina, Drizzle — mexanik. Mexanikada ko'proq narsani o'zingiz boshqarasiz, lekin yo'lni yaxshi bilsangiz, tezroq va tejamkorroq.
Real loyihalarda ikkalasi ham uchraydi; ishga kirganda qaysi biri bo'lishini oldindan bilmaysiz. Shuning uchun Drizzle'ni ham o'qiy va yoza olish kerak.
Bu darsning chiqishlarini biz ishga tushirdik: PostgreSQL 17.6 (holat 20 namunasi nusxasi), drizzle-orm 0.45.4, pg 8.23.1, Node 24.21.0. Drizzle'ning 1.0 versiyasi hozir (2026-10-25) RC — sinov bosqichida; npm'dagi barqaror latest — 0.45.4, biz shuni ishlatdik.
2. O'rnatish va sxema
2.1 Paketlar
npm i drizzle-orm@0.45.4 pg
npm i -D drizzle-kit@0.31.11 @types/pgdrizzle-orm — runtime (so'rov quruvchi). drizzle-kit — migratsiya CLI (dev, keyingi dars). Drayver — o'sha pg (Drizzle postgres.js va boshqalarni ham qo'llaydi).
2.2 pgTable: jadval TypeScript'da
Mavjud bazamizning bir qismini tasvirlaymiz (src/sxema.ts):
import {
bigint, boolean, integer, jsonb, pgEnum, pgTable, text, timestamp,
} from "drizzle-orm/pg-core";
export const ustuvorlik = pgEnum("ustuvorlik",
["past", "orta", "yuqori"]);
export const foydalanuvchilar = pgTable("foydalanuvchilar", {
id: bigint("id", { mode: "number" })
.primaryKey().generatedAlwaysAsIdentity(),
email: text("email").notNull(),
ism: text("ism").notNull(),
sozlamalar: jsonb("sozlamalar")
.$type<{ til?: string; mavzu?: string }>().notNull().default({}),
});
export const vazifalar = pgTable("vazifalar", {
id: bigint("id", { mode: "number" })
.primaryKey().generatedAlwaysAsIdentity(),
egasiId: bigint("egasi_id", { mode: "number" }).notNull()
.references(() => foydalanuvchilar.id),
matn: text("matn").notNull(),
bajarildi: boolean("bajarildi").notNull().default(false),
ustuvorlik: ustuvorlik("ustuvorlik").notNull().default("orta"),
muddat: timestamp("muddat", { withTimezone: true, mode: "date" }),
bajarilganVaqt: timestamp("bajarilgan_vaqt",
{ withTimezone: true, mode: "date" }),
izohlarSoni: integer("izohlar_soni").notNull().default(0),
versiya: integer("versiya").notNull().default(1),
tartib: integer("tartib"),
ochirilganVaqt: timestamp("ochirilgan_vaqt",
{ withTimezone: true, mode: "date" }),
});Uch narsaga qarang:
- Ikki nom: chapdagi
egasiId— TypeScript'dagi nom,"egasi_id"— bazadagi ustun. Prisma'dagi@mapning o'rni. bigintningmodei:"number"— JavaScriptnumber(2⁵³ gacha xavfsiz),"bigint"—bigint. Prisma doimbigintberardi; Drizzle'da tanlov sizda. Kanon hammode: "number"ni tanlagan.jsonb(...).$type<…>()— JSON ichining turi. Bu faqat TypeScript va'dasi: bazadan boshqa narsa kelsa, Drizzle tekshirmaydi.
Bu sxema — faqat tavsif. Jadval bazada allaqachon bor (26–27-qism SQL migratsiyalari). Biz Drizzle'ga "jadval shunday ko'rinishda" deyapmiz, xolos. tartib ni ixtiyoriy (.notNull() siz) qoldirdik: bazada NOT NULL, lekin uni trigger qo'yadi — Prisma sxemasidagi Int? qarorining o'zi.
2.3 Ulanish
import pg from "pg";
import { drizzle } from "drizzle-orm/node-postgres";
const pool = new pg.Pool({
connectionString: process.env.DATABASE_URL,
});
const db = drizzle(pool, {
logger: {
logQuery: (q, p) =>
console.log(`SQL: ${q} -- ${JSON.stringify(p)}`),
},
});Hovuz — bizniki (Connection pooling); Drizzle ustiga yupqa qatlam. logger — har SQL va parametrlar (Prisma'dagi $on("query") o'rni).
3. O'qish: select
3.1 Asosiy shakl
import { and, asc, eq } from "drizzle-orm";
await db.select({ id: vazifalar.id, matn: vazifalar.matn })
.from(vazifalar)
.where(and(
eq(vazifalar.egasiId, 2),
eq(vazifalar.bajarildi, false),
))
.orderBy(asc(vazifalar.id))
.limit(3);[
{ id: 14, matn: 'IELTS writing task 2 mashqi #ingliz' },
{ id: 26, matn: "Dugonamning tug'ilgan kuniga sovg'a #oila" },
{ id: 36, matn: 'Rezyume yangilash #ish' }
]
SQL: select "id", "matn" from "vazifalar" where ("vazifalar"."egasi_id" = $1 and "vazifalar"."bajarildi" = $2) order by "vazifalar"."id" asc limit $3 -- [2,false,3]Kod va SQL deyarli so'zma-so'z mos. id — 14 (son), Prisma'dagi 14n emas: mode: "number" ishladi. Qiymatlar — $1, $2, $3.
Shartlar — funksiyalar: eq (=), ne (<>), gt/gte/lt/lte, and, or, not, like/ilike, inArray, isNull/isNotNull, between. Prisma'dagi where obyekti o'rniga — SQL ifodasining o'zi.
3.2 select() — sxemadagi hamma ustun
const [v] = await db.select().from(vazifalar)
.where(eq(vazifalar.id, 2));
console.log(Object.keys(v ?? {}).join(", "));
console.log(typeof v?.id, v?.muddat instanceof Date, v?.ustuvorlik);id, egasiId, matn, bajarildi, ustuvorlik, muddat, bajarilganVaqt, izohlarSoni, versiya, tartib, ochirilganVaqt
number false orta
SQL: select "id", "egasi_id", "matn", "bajarildi", "ustuvorlik", "muddat", "bajarilgan_vaqt", "izohlar_soni", "versiya", "tartib", "ochirilgan_vaqt" from "vazifalar" where "vazifalar"."id" = $1 -- [2]"Hamma ustun" — bazadagi emas, sxemada yozilgan ustunlar: yaratilgan_vaqt va qidiruv ni sxemaga yozmadik — ular SQL'da ham yo'q. muddat instanceof Date — false: 2-vazifada muddat yo'q (null). Natija har doim massiv — bitta qator kerak bo'lsa, const [v] = … bilan olinadi.
3.3 Murakkab shart
await db.select({ id: vazifalar.id }).from(vazifalar).where(and(
inArray(vazifalar.egasiId, [1, 2]),
or(
ilike(vazifalar.matn, "%bozor%"),
eq(vazifalar.ustuvorlik, "yuqori"),
),
isNull(vazifalar.ochirilganVaqt),
)).orderBy(asc(vazifalar.id));[ { id: 1 }, { id: 14 }, { id: 16 }, { id: 23 }, { id: 28 }, { id: 48 } ]
SQL: select "id" from "vazifalar" where ("vazifalar"."egasi_id" in ($1, $2) and ("vazifalar"."matn" ilike $3 or "vazifalar"."ustuvorlik" = $4) and "vazifalar"."ochirilgan_vaqt" is null) order by "vazifalar"."id" asc -- [1,2,"%bozor%","yuqori"](Natija qatorlari qisqartirib bir qatorga yozildi.) ilike ga % ni o'zimiz yozdik — Drizzle contains kabi yordamchi bermaydi va jokerlarni ekranlamaydi. Foydalanuvchi matni bilan — SQL injection darsidagi likeEscape.
3.4 JOIN
await db.select({ matn: vazifalar.matn, egasi: foydalanuvchilar.ism })
.from(vazifalar)
.innerJoin(foydalanuvchilar,
eq(vazifalar.egasiId, foydalanuvchilar.id))
.where(eq(vazifalar.id, 16));[ { matn: 'Bozordan meva olish #bozor', egasi: 'Dilnoza Rahimova' } ]
SQL: select "vazifalar"."matn", "foydalanuvchilar"."ism" from "vazifalar" inner join "foydalanuvchilar" on "vazifalar"."egasi_id" = "foydalanuvchilar"."id" where "vazifalar"."id" = $1 -- [16]Haqiqiy SQL JOIN — bitta so'rov (JOIN'lar). Prisma'da bu include (alohida so'rovlar) bo'lardi. leftJoin da o'ng jadval maydonlari turi avtomatik | null bo'ladi.
Tekshirib ko'ring:
db.select().from(vazifalar)bazadagi 15 ta ustunning hammasini qaytaradimi?
Javob
Yo'q — faqat pgTable da yozilgan 11 tasini. Drizzle bazani "bilmaydi", u sxema faylingizga ishonadi. Sxemada yo'q ustun so'ralmaydi; sxemada bor, lekin bazada yo'q ustun so'ralsa — Postgres column … does not exist xatosini beradi.
4. Agregatlar va sql template
import { count, desc, sql } from "drizzle-orm";
await db.select({
egasi: vazifalar.egasiId,
soni: count(),
bajarilgan: sql<number>`count(*)
filter (where ${vazifalar.bajarildi})`.mapWith(Number),
}).from(vazifalar).groupBy(vazifalar.egasiId)
.orderBy(desc(count())).limit(3);[
{ egasi: 1, soni: 13, bajarilgan: 6 },
{ egasi: 4, soni: 9, bajarilgan: 4 },
{ egasi: 5, soni: 6, bajarilgan: 3 }
]
SQL: select "egasi_id", count(*), count(*) filter (where "bajarildi") from "vazifalar" group by "vazifalar"."egasi_id" order by count(*) desc limit $1 -- [3]sql template — Drizzle quruvchisida yo'q narsa uchun (FILTER, window funksiyalar, Postgres funksiyalari). ${vazifalar.bajarildi} — ustun nomi bo'lib qo'yildi. Oddiy qiymat bersangiz — $n parametr bo'ladi. sql<number> — natija turi (TypeScript va'dasi), .mapWith(Number) — haqiqiy aylantirish: count(*) Postgres'da bigint, pg uni satr qilib qaytaradi; mapWith uni songa aylantiradi. count() yordamchisi buni o'zi qiladi.
Faqat son kerak bo'lsa — $count:
$count: 6
SQL: select count(*) as count from "vazifalar" where "vazifalar"."egasi_id" = $1; -- [3]4.1 sql va sql.raw
const soz = "' OR 1=1 --";
await db.select({ id: vazifalar.id }).from(vazifalar)
.where(sql`${vazifalar.matn} = ${soz}`); // ✅
db.select({ id: vazifalar.id }).from(vazifalar)
.where(sql.raw(`matn = '${soz}'`)).toSQL().sql; // ❌0 qator
SQL: select "id" from "vazifalar" where "vazifalar"."matn" = $1 -- ["' OR 1=1 --"]
select "id" from "vazifalar" where matn = '' OR 1=1 --'sql — tagged template, qiymat parametr. sql.raw — matnni yopishtiradi: ikkinchi qatorda injection tayyor SQL (biz uni bajarmadik, faqat toSQL() bilan ko'rdik). Prisma'dagi Prisma.raw ning o'zi — faqat oq ro'yxat bilan (Prisma: raw SQL).
4.2 toSQL() — bajarmasdan ko'rish
db.select({ id: izohlar.id }).from(izohlar)
.where(eq(izohlar.vazifaId, 1)).toSQL();{
sql: 'select "id" from "izohlar" where "izohlar"."vazifa_id" = $1',
params: [ 1 ]
}Drizzle so'rovi — await qilinmaguncha shunchaki obyekt. toSQL() uni bazaga yubormasdan SQL va parametrlarni beradi — test va debug uchun qulay.
5. Yozish: insert, update, delete
5.1 insert … returning
await db.insert(vazifalar)
.values({ egasiId: 2, matn: "Drizzle bilan yaratildi #drizzle" })
.returning({
id: vazifalar.id,
tartib: vazifalar.tartib,
versiya: vazifalar.versiya,
});[ { id: 49, tartib: 7, versiya: 1 } ]
SQL: insert into "vazifalar" ("id", "egasi_id", "matn", "bajarildi", "ustuvorlik", "muddat", "bajarilgan_vaqt", "izohlar_soni", "versiya", "tartib", "ochirilgan_vaqt") values (default, $1, $2, default, default, default, default, default, default, default, default) returning "id", "tartib", "versiya" -- [2,"Drizzle bilan yaratildi #drizzle"]SQL'ga qarang: Drizzle sxemadagi hamma ustunni yozdi, berilmaganlariga — default. Prisma esa sukut qiymatlarini o'zi yuborardi (Prisma Client CRUD). Natija bir xil: tartib ni trigger qo'ydi (7), RETURNING uni qaytardi. Bir nechta qator — .values([{…}, {…}]) — bitta INSERT.
5.2 update va delete
await db.update(vazifalar)
.set({
bajarildi: true,
bajarilganVaqt: new Date("2026-10-25T06:00:00Z"),
})
.where(eq(vazifalar.matn, "Non olish"))
.returning({ id: vazifalar.id, versiya: vazifalar.versiya });
await db.delete(vazifalar)
.where(eq(vazifalar.matn, "Suv olish"))
.returning({ id: vazifalar.id, matn: vazifalar.matn });[ { id: 50, versiya: 2 } ]
SQL: update "vazifalar" set "bajarildi" = $1, "bajarilgan_vaqt" = $2 where "vazifalar"."matn" = $3 returning "id", "versiya" -- [true,"2026-10-25T06:00:00.000Z","Non olish"]
[ { id: 51, matn: 'Suv olish' } ]
SQL: delete from "vazifalar" where "vazifalar"."matn" = $1 returning "id", "matn" -- ["Suv olish"]Prisma'dagi P2025 yo'q: hech narsa topilmasa — bo'sh massiv []. "Topilmadi" holatini o'zingiz tekshirasiz (returning uzunligi).
5.3 Tuzoq: where siz update
await db.transaction(async (tx) => {
const r = await tx.update(vazifalar)
.set({ bajarildi: false, bajarilganVaqt: null })
.returning({ id: vazifalar.id });
console.log("o'zgargan qatorlar:", r.length);
tx.rollback();
});o'zgargan qatorlar: 50
tranzaksiya: Rollback
SQL: begin -- []
SQL: update "vazifalar" set "bajarildi" = $1, "bajarilgan_vaqt" = $2 returning "id" -- [false,null]
SQL: rollback -- []Drizzle ogohlantirmadi — jadvaldagi hamma 50 ta vazifa o'zgardi (biz uni tx.rollback() bilan qaytardik; rollback() maxsus xato otadi, shuning uchun Rollback xabari). SQL'dagi UPDATE ning o'zi ham shunday (UPDATE va DELETE xavfsiz) — Drizzle "SQL kabi" va'dasini bu yerda ham bajaradi. Himoya: kod review, ESLint uchun eslint-plugin-drizzle (enforce-update-with-where, enforce-delete-with-where qoidalari — Drizzle hujjati, sinalmagan).
5.4 Xatolar
CHECK cheklovini buzdik (bo'sh matn):
DrizzleQueryError | Failed query: insert into "vazifalar" ("id", "egasi_id", "matn", "bajarildi", "ustuvorlik", "muddat", "bajarilgan_vaqt", "izohlar_soni", "versiya", "tartib", "ochirilgan_vaqt") values (default, $1, $2, default, default, default, default, default, default, default, default)
cause: 23514 vazifalar_matn_checkDrizzle xatoni DrizzleQueryError ga o'raydi, asl pg xatosi — cause da: Postgres kodi (23514) va cheklov nomi. Prisma'dagi P-kodlar yo'q — siz to'g'ridan SQLSTATE bilan ishlaysiz (26-qismdagi PgOmbori dagidek).
6. Tip xulosasi
export type Vazifa = typeof vazifalar.$inferSelect;
export type YangiVazifa = typeof vazifalar.$inferInsert;$inferSelect — o'qilgan qator turi, $inferInsert — yozish uchun: sukutli ustunlar ixtiyoriy, generatedAlwaysAsIdentity li id umuman yo'q. Biz tsc (TypeScript 6.0.3, strict) bilan sinadik:
const y2: YangiVazifa = { egasiId: 2 };
const y3: YangiVazifa = {
egasiId: 2, matn: "Non", ustuvorlik: "juda",
};TS2741: Property 'matn' is missing in type '{ egasiId: number; }' but required in type '{ egasiId: number; matn: string; ustuvorlik?: "past" | "orta" | "yuqori" | undefined; …'.
TS2322: Type '"juda"' is not assignable to type '"past" | "orta" | "yuqori" | undefined'.(Birinchi xabar uzun — qisqartirildi.) matn majburiy (notNull(), sukutsiz), enum faqat uch qiymat. Bu turlar Prisma'nikiga o'xshaydi — farqi shundaki, prisma generate siz, TypeScript generic'lari bilan (Generics: turni parametr qilish) to'g'ridan sxemadan chiqadi: sxemani o'zgartirsangiz, turlar darhol o'zgaradi.
flowchart LR
S["sxema.ts (pgTable)"] --> T["$inferSelect / $inferInsert"]
S --> Q["db.select().from().where()"]
Q --> SQL["SQL + params"]
SQL --> PG[("Postgres")]
T -.-> QDiagrammaga qarang: bitta manba — sxema.ts. Undan ham turlar, ham so'rovlar chiqadi; o'rtada generatsiya qadami yo'q (Prisma'da schema.prisma → generate → klient).
7. Drizzle, Prisma va pg — o'lchov
Kanon bir xil uch savolni har kutubxona bilan o'lchagan (katta bazasi, 500 000 vazifa, egasi 77, mediana 30; A — ro'yxat 50, B — 50 vazifa + izohlari, C — INSERT + ROLLBACK). Chiqishda A_ms, B_ms, C_ms raqamlarini va A[0] dagi id turini solishtiring:
paket pg@8.23.1: o'zi 179K, bevosita bog'liqliklar 5
paket drizzle-orm@0.45.4: o'zi 16M, bevosita bog'liqliklar 0
{"nom":"pg","import_va_ulanish_ms":0,"A_qator":50,"B_qator":50,"B_sql_soni":"—","A_ms":"1.00","B_ms":"1.34","C_ms":"2.41"}
A[0]: {"id":"709","matn":"Kitob o'qish 709 #uy","tartib":709}
jarayon jami: 395 ms
{"nom":"drizzle","import_va_ulanish_ms":404,"A_qator":50,"B_qator":50,"B_sql_soni":1,"A_ms":"1.08","B_ms":"1.61","C_ms":"2.47"}
A[0]: {"id":709,"matn":"Kitob o'qish 709 #uy","tartib":709}
jarayon jami: 862 ms(Kanon chiqishidan pg va Drizzle qatorlari, aynan.) A[0] ga qarang: pg da id — "709" satr, Drizzle'da — 709 son (mode: "number"). Drizzle pg dan atigi 0.08 ms sekin; relation bilan so'rov (B) bitta SQL. Prisma'ning shu "ro'yxat 50" o'lchovi — 4.43 ms (boshqa o'lchov skripti — VazifaOmbori orqali, to'g'ridan solishtirib bo'lmaydi, lekin tartibi ko'rinadi). Paket 16 MB — Prisma klientining (72 MB) beshdan biri, bog'liqliksiz.
8. Ko'p uchraydigan xatolar
| Belgi | Sabab | Davosi |
|---|---|---|
update/delete hamma qatorni o'zgartirdi |
where yo'q |
review, eslint-plugin-drizzle |
count natijasi "13" satr |
bigint → pg satr |
count() yoki .mapWith(Number) |
column … does not exist |
sxemadagi nom bazadagidan farqli | "egasi_id" ni tekshiring |
% hammasini topdi |
ilike jokerlari ekranlanmagan |
likeEscape |
injection sql.raw da |
matn yopishtirilgan | sql template, oq ro'yxat |
jsonb turida noto'g'ri ma'lumot |
$type<> — faqat va'da |
Zod bilan tekshirish |
9. Mashqlar
Mashqlar kurs/mashqlar/27/29-drizzle-sorovlar/ da. 2-mashq yechimi Node 24 da tekshirilgan (bazasiz); 3-mashqni biz bazada ishga tushirdik.
1-mashq (oson): Drizzle funksiyalari
egasi_id = 2—(vazifalar.egasiId, 2)ochirilgan_vaqt IS NULL—(vazifalar.ochirilganVaqt)- O'qilgan qator turi —
typeof vazifalar.$ - SQL'ni bajarmasdan ko'rish —
.()
Yechim
- eq — tenglik.
- isNull —
IS NULL. - inferSelect —
$inferInsert— yozish uchun. - toSQL —
{ sql, params }.
2-mashq (o'rta): debug uchun SQL'ni "to'ldirish"
toSQL() natijasi { sql, params }. Log'da o'qish oson bo'lishi uchun toldir({ sql, params }) funksiyasini yozing: $1, $2… o'rniga qiymatni qo'ysin — satr '…' ichida (ichidagi ' ikkilangan), null — NULL, son va boolean — o'zicha. Faqat ko'rsatish uchun: bunday satrni bazaga yuborish taqiqlanadi.
Yechim
function qiymat(x) {
if (x === null || x === undefined) return "NULL";
if (typeof x === "number" || typeof x === "boolean") {
return String(x);
}
return `'${String(x).replaceAll("'", "''")}'`;
}
function toldir({ sql, params }) {
return sql.replace(/\$(\d+)/g,
(_, n) => qiymat(params[Number(n) - 1]));
}
console.log(toldir({
sql: 'select "id" from "vazifalar" ' +
'where "matn" = $1 and "egasi_id" = $2',
params: ["Dilnoza'ning ishi", 2],
}));
console.log(toldir({
sql: "update t set a = $1, b = $10 where c = $2",
params: [true, null, 3, 4, 5, 6, 7, 8, 9, "o'n"],
}));Konsolda:
select "id" from "vazifalar" where "matn" = 'Dilnoza''ning ishi' and "egasi_id" = 2
update t set a = true, b = 'o''n' where c = NULL/\$(\d+)/g raqamni to'liq oladi — $10 ni $1 + 0 deb buzmaydi. ' ning ikkilanishi — SQL satr qoidasi. Nega bazaga yuborilmaydi: bu — qo'lda escape, injection'ga qarshi kafolat emas; parametr (SQL injection) — yagona to'g'ri yo'l.
3-mashq (qiyin): filtr va son bitta shart bilan
Azizning (1) bajarilmagan, o'chirilmagan, #o'qish tegli vazifalarini id bo'yicha oling va xuddi shu shart bilan ularning sonini hisoblang. Shartni bir marta yozing.
Yechim
import { and, asc, count, eq, isNull, like } from "drizzle-orm";
const shart = and(
eq(vazifalar.egasiId, 1),
eq(vazifalar.bajarildi, false),
isNull(vazifalar.ochirilganVaqt),
like(vazifalar.matn, "%#o'qish%"),
);
const royxat = await db
.select({ id: vazifalar.id, matn: vazifalar.matn })
.from(vazifalar)
.where(shart)
.orderBy(asc(vazifalar.id));
const [{ soni }] = await db
.select({ soni: count() }).from(vazifalar).where(shart);
console.log(soni, royxat.map((v) => v.id));Biz ishga tushirdik (PostgreSQL 17.6, drizzle-orm 0.45.4):
1 [ 1 ]Azizning #o'qish tegli vazifalaridan faqat 1-si bajarilmagan. Asosiy g'oya: Drizzle sharti — oddiy qiymat (SQL obyekti), uni o'zgaruvchiga olib, bir nechta so'rovda qayta ishlatish mumkin. Bu — 26-qismdagi shartlar massivining Drizzle shakli.
10. Loyiha qadami: kanon tajribasi, loyihaga kirmaydi
vazifalar-api Drizzle'ga ko'chmaydi. Kanon Drizzle'ni (va boshqa to'rt kutubxonani) alohida tajriba papkasida, bir xil uch savol bilan o'lchadi — natijalar «Drizzle, Prisma va pg — o'lchov» bo'limida. Kanon qarori (o'lchov bilan, ORM tanlash qo'llanmasi darsida to'liq): API — Prisma (asosiy) + pg (taqqoslash va raw SQL); Drizzle va Kysely — eng yaqin muqobil (kichik, SQL'ga yaqin, tez). Bitta loyihada ikki ORM — ikki marta ko'p tur, migratsiya va test; o'rganish uchun tajriba yetarli.
Siz o'z tajribangizni qilmoqchi bo'lsangiz — bo'sh papkada npm init -y, shu darsdagi sxema.ts va lokal bazangiz (26-qismdagi namuna).
11. Real ishda
- Drizzle ko'pincha serverless va edge muhitlarida (Cloudflare Workers, Vercel) tanlanadi: kichik hajm, bog'liqliksiz paket va generatsiya qadamining yo'qligi u yerda muhim.
- Ish e'lonlarida "Prisma yoki Drizzle" juft holda uchraydi; birini bilgan odam ikkinchisini tez o'rganadi — g'oyalar bir xil, sintaksis boshqa.
- Intervyuda: "Drizzle va Prisma farqi?", "Drizzle turlarni qanday chiqaradi?", "
sqlvasql.rawfarqi?"
Xulosa
- Drizzle sxemasi —
pgTablebilan TypeScript fayl; TS nomi va bazadagi nom alohida (egasiId/"egasi_id"). - So'rov SQL tartibida:
select().from().where().orderBy().limit(); shartlar —eq,and,or,ilike,inArray,isNull. insert/update/delete … returning; topilmasa — bo'sh massiv;wheresizupdate— hamma qator (50/50).sql— parametrli template,sql.raw— yopishtiradi;toSQL()— bajarmasdan ko'rish.- Turlar generatsiyasiz:
$inferSelect/$inferInsert. Kanon:pg1.00 ms, Drizzle 1.08 ms, paket 16 MB.
Keyingi dars: Drizzle ORM 2: relations va drizzle-kit — relations(), db.query…findMany({ with }), tranzaksiya va migratsiya CLI.
Manbalar
- Drizzle hujjati — PostgreSQL column types: https://orm.drizzle.team/docs/column-types/pg (2026-10-25)
- Drizzle hujjati — Select, Insert, Update, Delete: https://orm.drizzle.team/docs/select
- Drizzle hujjati — Operators (
eq,and, …): https://orm.drizzle.team/docs/operators - Drizzle hujjati — Magic
sqloperator: https://orm.drizzle.team/docs/sql - Drizzle hujjati — ESLint plugin: https://orm.drizzle.team/docs/eslint-plugin
- Chiqishlar — biz ishga tushirdik: PostgreSQL 17.6, drizzle-orm 0.45.4, pg 8.23.1, TypeScript 6.0.3, Node 24.21.0 (2026-10-25); taqqoslash o'lchovi — kanon (PostgreSQL 18.6).
Izohlar (0)
Izoh yozish uchun kiring.
- Hozircha izoh yo'q. Birinchi bo'ling!