IlmHamroh
JavaScript Full-stack/27-qism. Ma'lumotlar bazasi chuqur: Postgres, ORM, Mongo, Redis29/65-dars16 daqiqa
Mundarija (30)

Drizzle ORM: pgTable sxemasi, select/insert/update va tip xulosasi

Qisqacha: Drizzle — "SQL'ga o'xshagan TypeScript": sxema .ts faylda pgTable(...) 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 tezligi pg ga yaqin (ro'yxat 1.08 ms vs 1.00 ms). Tuzoq: update ni where siz yozsangiz — xato yo'q, biz sinadik: 50 qatorning hammasi o'zgardi.

Bu darsda

  • Mavjud bazaga Drizzle sxemasini pgTable bilan yozasiz.
  • select, insert, update, delete so'rovlarini quruvchi bilan yozasiz va SQL'ini o'qiysiz.
  • eq, and, or, ilike, inArray, isNull va sql template'ni ishlatasiz.
  • $inferSelect/$inferInsert turlarini va TypeScript xatolarini o'qiysiz.
  • Drizzle'ni Prisma va raw pg bilan 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

bash
npm i drizzle-orm@0.45.4 pg
npm i -D drizzle-kit@0.31.11 @types/pg

drizzle-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):

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 @map ning o'rni.
  • bigint ning modei: "number" — JavaScript number (2⁵³ gacha xavfsiz), "bigint" — bigint. Prisma doim bigint berardi; Drizzle'da tanlov sizda. Kanon ham mode: "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

ts
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

ts
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);
text
[
  { 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

ts
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);
text
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

ts
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));
text
[ { 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

ts
await db.select({ matn: vazifalar.matn, egasi: foydalanuvchilar.ism })
  .from(vazifalar)
  .innerJoin(foydalanuvchilar,
    eq(vazifalar.egasiId, foydalanuvchilar.id))
  .where(eq(vazifalar.id, 16));
text
[ { 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

ts
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);
text
[
  { 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:

text
$count: 6
SQL: select count(*) as count from "vazifalar" where "vazifalar"."egasi_id" = $1; -- [3]

4.1 sql va sql.raw

ts
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;  // ❌
text
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

ts
db.select({ id: izohlar.id }).from(izohlar)
  .where(eq(izohlar.vazifaId, 1)).toSQL();
text
{
  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

ts
await db.insert(vazifalar)
  .values({ egasiId: 2, matn: "Drizzle bilan yaratildi #drizzle" })
  .returning({
    id: vazifalar.id,
    tartib: vazifalar.tartib,
    versiya: vazifalar.versiya,
  });
text
[ { 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

ts
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 });
text
[ { 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

ts
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();
});
text
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):

text
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_check

Drizzle 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

ts
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:

ts
const y2: YangiVazifa = { egasiId: 2 };
const y3: YangiVazifa = {
  egasiId: 2, matn: "Non", ustuvorlik: "juda",
};
text
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 -.-> Q

Diagrammaga 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:

text
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
js
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:

text
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
ts
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):

text
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?", "sql va sql.raw farqi?"

Xulosa

  • Drizzle sxemasi — pgTable bilan 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; where siz update — hamma qator (50/50).
  • sql — parametrli template, sql.raw — yopishtiradi; toSQL() — bajarmasdan ko'rish.
  • Turlar generatsiyasiz: $inferSelect/$inferInsert. Kanon: pg 1.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

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Drizzle ORM: pgTable sxemasi, select/insert/update va tip xulosasi — IlmHamroh