WisarWisar
Dasturlash kitobi/6-QISM — Database22 daqiqa

6.12-bob: ORM — Prisma (schema, migrate, client, relations)

6-QISM — Ma'lumotlar bazasi (Database) · 12-mavzu


1. Kirish va motivatsiya

Sequelize (klassik ORM — 6.11) ni bildik. Endi zamonaviy, type-safe (tur-xavfsiz) ORM — Prisma ga o'tamiz. Prisma — bugungi kunda yangi loyihalar uchun eng ko'p tavsiya etiladigan ORM (ayniqsa TypeScript bilan). Sababi: u boshqacha, deklarativ yondashuvni qo'llaydi — bitta schema.prisma faylda butun ma'lumot modelini ta'riflaysiz, Prisma esa undan avtomatik type-safe client generatsiya qiladi. Bu — ajoyib developer experience (avtomat to'ldirish, tur tekshiruvi, xatolarni kompilyatsiyada ushlash).

Sequelize'da modellarni JS kodida (define) yozdik. Prisma'da — alohida schema fayl (schema.prisma) — barcha modellar, bog'lanishlar, sozlamalar bir joyda, o'qiladigan. Keyin prisma generate — schema'dan Prisma Client (tur bilan) yaratadi. prisma migrate — schema'ni DB'ga qo'llaydi (migration avtomatik). Bu — schema yagona haqiqat manbai (single source of truth): schema o'zgarsa, client va DB ham (sinxron).

Prisma'ning eng kuchli tomoni — type-safety: TypeScript (7) bilan har so'rov, natija, maydon tur bilan (autocompletion, xato kompilyatsiyada). user.emial (typo) — Prisma'da kompilyatsiya xatosi (Sequelize'da runtime'da bilinadi). 2025-yil oxirida Prisma 7 chiqdi — to'liq TypeScript runtime (3x tezroq). Bu bob: schema, migrate, client, relations, va type-safe so'rovlar — chuqur.

O'xshatish: Sequelize — qo'lda yasalgan mebel (har bo'lakni o'zingiz kesasiz/yig'asiz — moslashuvchan, lekin ko'p ish). Prisma — IKEA to'plami: chizma (schema.prisma) bo'yicha tayyor, aniq bo'laklar (generatsiya qilingan client) — tez yig'asiz, hammasi mos keladi (type-safe), xato kam. Chizmani o'zgartirsangiz, bo'laklar ham (migrate). Zamonaviy, ishonchli.

Nega muhim?

  • Zamonaviy tanlov — yangi loyiha (ayniqsa TS) uchun eng ko'p tavsiya.
  • Type-safety — xatolarni kompilyatsiyada ushlash (runtime'da emas).
  • DX — schema, avtomat client, autocompletion — tez, kam xato.
  • Stack talabi — Prisma sizning stack'ingda; NestJS, Next.js bilan a'lo.

2. Nazariya — chuqur tushuntirish

2.1. Prisma nima va arxitekturasi

Prisma — zamonaviy, type-safe ORM (prisma.io). Uch qismdan iborat:

text
  1. Prisma Schema (schema.prisma) — ma'lumot modeli (yagona manba)
  2. Prisma Client — schema'dan AVTOMATIK generatsiya (type-safe so'rovlar)
  3. Prisma Migrate — schema'ni DB'ga qo'llash (migration)

  Oqim:
  schema.prisma yozing  prisma generate (client)  prisma migrate (DB)  kodda ishlating

Asosiy farq (Sequelize'dan): Sequelize'da model — JS kod. Prisma'da — deklarativ schema fayl + avtomatik client. Schema — yagona haqiqat (single source of truth): undan ham client, ham DB hosil bo'ladi (sinxron).

2.2. Type-safety (eng kuchli tomon)

text
  Sequelize (tur yo'q to'liq):
  const user = await User.findByPk(1);
  user.emial    // typo  RUNTIME'da undefined (xato keyin bilinadi)

  Prisma (type-safe — TS):
  const user = await prisma.user.findUnique({ where: { id: 1 } });
  user.emial    //  KOMPILYATSIYA xatosi (darrov bilinadi — TS — 7)
  user.email    //  autocompletion, tur bilan

Type-safety qiymati (talent500): Prisma TypeScript (7) bilan har narsani tipladi — model, so'rov, natija, maydon. Xato kompilyatsiyada (runtime'da emas — ishlatishdan oldin). Bu — ishonchlilik va tezlikni keskin oshiradi (autocompletion, refactoring xavfsiz).

2.3. O'rnatish va init

bash
npm install prisma --save-dev      # CLI
npm install @prisma/client          # client
npx prisma init                     # schema.prisma + .env yaratadi
text
  Hosil bo'ladi:
  prisma/schema.prisma   — schema fayl 2.4-bob
  .env                   — DATABASE_URL (5.8)

2.4. Prisma Schema (schema.prisma)

Schema — butun ma'lumot modeli bir faylda (prisma.io):

prisma
// prisma/schema.prisma
generator client {
  provider = "prisma-client-js"     // client generatsiyasi
}

datasource db {
  provider = "postgresql"           // DB turi (mysql, sqlite, mongodb ham)
  url      = env("DATABASE_URL")    // .env (5.8)
}

model User {
  id        Int      @id @default(autoincrement())   // PK, avto (6.4)
  ism       String
  email     String   @unique                          // noyob (6.4)
  yosh      Int?                                       // ? — ixtiyoriy (nullable)
  rol       Role     @default(USER)                    // enum (2.5)
  orders    Order[]                                    // bog'lanish (one-to-many — 2.6)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt                        // avtomatik (6.2)
}

enum Role { USER ADMIN }                               // enum

Schema sintaksisi: model (jadval), maydon: nom + tur + atributlar (@id, @unique, @default, @updatedAt). ? — nullable (ixtiyoriy). Int? (NULL bo'lishi mumkin), Int (majburiy). Order[] — bog'lanish (massiv). Toza, o'qiladigan, bir joyda.

2.5. Maydon turlari va atributlar

prisma
model Product {
  id          Int      @id @default(autoincrement())
  nom         String   @db.VarChar(100)               // DB tur (VARCHAR(100))
  narx        Decimal  @db.Decimal(10, 2)             // DECIMAL (pul — 6.4: 2.3)
  tavsif      String?  @db.Text                        // ixtiyoriy, uzun
  faol        Boolean  @default(true)
  xususiyat   Json?                                    // JSONB (6.6: 2.10)
  teglar      String[]                                 // massiv (PostgreSQL — 6.6: 2.13)
  slug        String   @unique
  @@index([nom])                                       // indeks (6.10)
  @@map("products")                                    // jadval nomi
}

Atributlar: maydon (@) — @id, @unique, @default, @db.X (aniq DB tur). Model (@@) — @@index, @@unique, @@map (jadval nomi). Decimal (pul), Json (JSONB), String[] (massiv) — DB imkoniyatlari schema'da.

2.6. Relations (bog'lanishlar)

prisma
// One-to-Many: User  ko'p Order
model User {
  id     Int     @id @default(autoincrement())
  orders Order[]                                       // bir user — ko'p order
}
model Order {
  id     Int  @id @default(autoincrement())
  user   User @relation(fields: [userId], references: [id])   // bog'lanish (FK)
  userId Int                                           // FK ustun
  summa  Decimal @db.Decimal(10, 2)
}
prisma
// Many-to-Many (Prisma avtomatik junction jadval yaratadi)
model Post { id Int @id @default(autoincrement()); tags Tag[] }
model Tag  { id Int @id @default(autoincrement()); posts Post[] }

@relation — bog'lanishni belgilaydi (FK — fields/references — 6.1: 2.5). One-to-many: bir tomonda massiv (Order[]), boshqasida obyekt + FK (user/userId). Many-to-many — ikki tomonda massiv; Prisma junction jadvalni avtomatik yaratadi (Sequelize'da qo'lda — 6.11: 2.8).

2.7. Migrate (schema DB)

Prisma Migrate — schema o'zgarishini DB'ga qo'llaydi (avtomatik migration — prisma.io):

bash
npx prisma migrate dev --name init      # dev: migration yaratadi + qo'llaydi
npx prisma migrate deploy                # production: mavjud migration'larni qo'llaydi
npx prisma migrate reset                 # DB'ni tozalab, qayta (dev — ehtiyot!)

Sequelize'dan farq: Sequelize'da migration qo'lda yozasiz (6.11: 2.11). Prisma — schema'ni o'zgartirasiz, migrate dev avtomatik SQL migration yaratadi (farqni hisoblab). Migration fayllar (prisma/migrations/) — git'da (4). Production'da migrate deploy.

2.8. Generate (client yaratish)

bash
npx prisma generate      # schema'dan Prisma Client generatsiya
text
  schema.prisma  prisma generate  @prisma/client (type-safe)

  Schema O'ZGARSA  qayta generate (client yangilanadi — type bilan)
  migrate dev avtomatik generate ham qiladi

prisma generate — schema'dan TypeScript client (tur bilan) yaratadi. Schema o'zgarsa — qayta generate (yangi turlar). Bu — type-safety'ning manbai 2.2-bob: client schema'ga aniq mos (autocompletion).

2.9. Prisma Client — CRUD

js
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();                     // client (2.10: bir marta)

// CREATE
await prisma.user.create({ data: { ism: "Ali", email: "ali@a.uz" } });

// READ
await prisma.user.findMany();                          // hammasi
await prisma.user.findUnique({ where: { id: 1 } });    // PK/unique
await prisma.user.findFirst({ where: { rol: "ADMIN" } });
await prisma.user.findMany({ where: { yosh: { gt: 18 } } });   // operator (2.11)

// UPDATE
await prisma.user.update({ where: { id: 1 }, data: { yosh: 26 } });

// DELETE
await prisma.user.delete({ where: { id: 1 } });

Prisma so'rovlari — obyekt asosli (where, data, include, select). findUnique (PK/unique), findFirst (bitta shartli), findMany (ko'p). Hammasi type-safe (model maydonlari autocompletion).

2.10. PrismaClient — bir marta (singleton)

PrismaClientbir marta yaratiladi (ko'p instance — ulanish tugaydi):

js
// lib/prisma.js — singleton (2.10)
import { PrismaClient } from "@prisma/client";

const globalForPrisma = globalThis;
export const prisma = globalForPrisma.prisma || new PrismaClient();
if (process.env.NODE_ENV !== "production") globalForPrisma.prisma = prisma;
// Dev'da hot-reload har safar yangi client yaratmasligi uchun (Next.js — 13)

PrismaClient singleton: har so'rovda/faylda yangi PrismaClient() — ko'p ulanish DB ulanishlari tugaydi. Bir marta yarating, import qiling (6.5: pool kabi). Dev'da (hot-reload — Next.js) globalThis bilan saqlash (manba).

Nega singleton muhim? Chunki har bir PrismaClient o'z ulanish hovuzini (connection pool — 6.5) ochadi. Prisma ulanishlarni qayta ishlatadi (har so'rovga yangi ulanish emas — bu 6.5'dagi pool g'oyasi):

text
  PrismaClient (1 dona)
    └── ulanish hovuzi (pool) — bir nechta tayyor ulanish
          so'rov  hovuzdan ulanish olinadi  ishlatiladi  hovuzga qaytariladi

  Ko'p PrismaClient  ko'p hovuz  DB ulanish limiti tugaydi (xato)

Hovuz o'lchamini DATABASE_URL da sozlash mumkin:

text
  postgresql://user:pass@host:5432/db?connection_limit=10

Connection pool 6.5-bob: bitta PrismaClient — bitta hovuz (default o'lcham: num_cpu * 2 + 1). Serverless (Vercel, Lambda) da har funksiya alohida hovuz ochadi — DB limiti tez tugaydi; shuning uchun Prisma Accelerate yoki pgbouncer (tashqi pooler) ishlatiladi. Odatiy serverda singleton 2.10-bob yetarli. connection_limit — hovuzdagi maksimal ulanish.

2.11. So'rov operatorlari va filtrlash

js
await prisma.product.findMany({
  where: {
    narx: { gte: 1000, lte: 5000 },                    // oraliq (>=, <=)
    kategoriya: { in: ["telefon", "kompyuter"] },      // IN
    nom: { contains: "phone", mode: "insensitive" },   // LIKE (matn qidiruv)
    OR: [{ faol: true }, { zaxira: { gt: 0 } }],        // OR
  },
  orderBy: { narx: "desc" },                            // ORDER BY (6.4)
  take: 10, skip: 20,                                   // limit, offset (sahifalash)
  select: { id: true, nom: true, narx: true },          // SELECT ustunlar
});

Operatorlar: gt/gte/lt/lte (taqqoslash), in/notIn, contains/startsWith (matn), AND/OR/NOT. take/skip (limit/offset — 6.4: 2.10), orderBy, select (ustunlar). MongoDB 6.2-bob va Sequelize Op 6.11-bob ga o'xshash, lekin type-safe.

2.12. Relations bilan ishlash (include / select)

Include — bog'langan ma'lumotni birga olish (JOIN — eager — prisma.io):

js
// User + buyurtmalari (include — JOIN)
const user = await prisma.user.findUnique({
  where: { id: 1 },
  include: { orders: true },                            // buyurtmalarni ham (type-safe)
});
console.log(user.orders);                               // tur bilan!

// Nested include + shart + select
await prisma.user.findMany({
  include: {
    orders: {
      where: { holat: "tugallandi" },                   // shartli
      include: { items: { include: { product: true } } },   // ichma-ich
    },
  },
});

include (eager — N+1 oldini oladi — 2.16) — bog'langan ma'lumotni type-safe olib keladi (natija to'g'ri tiplangan — manba). select — faqat kerakli maydonlar. Nested — ichma-ich (user order item product). Sequelize include'iga o'xshash, lekin tur bilan.

2.13. Nested write (bog'liq ma'lumotni birga yozish)

Prisma bitta so'rovda bog'liq ma'lumot yaratadi (nested write — tranzaksiya — prisma.io):

js
// User + uning buyurtmasi BIRGA (bitta tranzaksiyada)
await prisma.user.create({
  data: {
    ism: "Ali", email: "ali@a.uz",
    orders: {                                           // bog'liq order birga (nested)
      create: [{ summa: 50000 }, { summa: 30000 }],     // ikkita order
    },
  },
  include: { orders: true },
});
// User + 2 order BITTA tranzaksiyada (biri xato bo'lsa — hammasi rollback — 2.14)

Nested write — bog'liq ma'lumotni bir so'rovda, atomik (prisma.io). create, connect (mavjudga ulash), connectOrCreate, update. Bu — tranzaksiya kafolati 2.14-bob bilan. Sequelize'da ko'p qadam kerak edi; Prisma — bir so'rov.

2.14. Tranzaksiya

js
// 1. Nested write — avtomatik tranzaksiya (2.13)
// 2. Bulk amallar (createMany/updateMany/deleteMany) — avtomatik tranzaksiya

// 3. Interactive transaction (murakkab mantiq — 6.9)
await prisma.$transaction(async (tx) => {
  const from = await tx.account.update({ where: { id: 1 }, data: { balans: { decrement: 100 } } });
  if (from.balans < 0) throw new Error("Balans yetarli emas");   //  rollback
  await tx.account.update({ where: { id: 2 }, data: { balans: { increment: 100 } } });
});
// xato bo'lsa — avtomatik ROLLBACK (6.9: ACID)

// 4. Sequential transaction (mustaqil amallar)
await prisma.$transaction([
  prisma.user.create({ ... }),
  prisma.order.create({ ... }),
]);

Prisma tranzaksiya — 4 usul: nested write 2.13-bob, bulk (avtomatik), $transaction(async tx) (interactive — murakkab mantiq, 6.9), $transaction([...]) (massiv — mustaqil). increment/decrement — atomik (6.9: 2.11). Xato avtomatik rollback.

2.15. Prisma Studio (vizual DB)

bash
npx prisma studio      # brauzerda DB'ni ko'rish/tahrirlash (GUI)

Prisma Studio — DB'ni brauzerda ko'rish/tahrirlash (admin panel kabi). Dev'da juda qulay (ma'lumotni ko'rish, test). Prisma'ning DX afzalliklaridan.

2.16. N+1 va performance

text
   N+1 (tsiklda alohida — 6.10: 2.11):
  const users = await prisma.user.findMany();
  for (const u of users) await prisma.order.findMany({ where: { userId: u.id } });

   include (bir so'rov — 2.12):
  await prisma.user.findMany({ include: { orders: true } });

Prisma N+1'ni include bilan oldini oladi 2.12-bob. Prisma so'rov logini ko'rsatish: new PrismaClient({ log: ["query"] }) — generatsiya SQL'ni ko'rish (2.14, 6.10). Murakkab so'rov uchun $queryRaw (xom SQL, type-safe parametr).

2.17. Prisma vs Sequelize vs TypeORM (taqqoslash)

text
  ┌──────────────┬──────────────┬──────────────┬──────────────┐
  │              │ Prisma       │ Sequelize    │ TypeORM      │
  ├──────────────┼──────────────┼──────────────┼──────────────┤
  │ Yondashuv    │ schema fayl  │ JS model     │ class+dekor. │
  │ Type-safety  │  a'lo      │ ~            │  yaxshi    │
  │ DX           │  a'lo      │ o'rtacha     │ yaxshi       │
  │ Migration    │ avtomatik    │ qo'lda       │ avtomatik    │
  │ NestJS       │ yaxshi       │ ~            │  tabiiy    │
  │ Murakkab SQL │ raw          │ raw          │ query builder│
  └──────────────┴──────────────┴──────────────┴──────────────┘

Tanlov (2026): Prisma — yangi loyiha, TS, DX muhim (eng ko'p tavsiya). TypeORM — NestJS bilan tabiiy (dekorator — 6.13, 8). Sequelize — mavjud loyiha, JS. Uchchovi ham yaxshi; Prisma — zamonaviy yetakchi.

2.18. Xavfsizlik va best practices (14)

text
   PrismaClient singleton (bir marta — 2.10)
   Migration (migrate dev/deploy — qo'lda emas — 2.7, 14)
   include o'ylab (N+1 oldini oling, ortiqcha emas — 2.12, 2.16)
   select bilan kerakli maydonlar (maxfiy yashiring — parol — 2.11)
   Tranzaksiya ($transaction — ko'p yozuv — 2.14)
   $queryRaw parametrli (injection — 14, 2.16)
   DATABASE_URL .env'da (14, 5.8)
   log: ["query"] (dev) — SQL ko'rish (2.16)

3. Sintaksis — tez ma'lumotnoma

prisma
// schema.prisma (2.4)
model User { id Int @id @default(autoincrement()); email String @unique; orders Order[] }
js
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();                     // singleton (2.10)

await prisma.user.create({ data: {...} });             // C (2.9)
await prisma.user.findUnique({ where: { id } });       // R
await prisma.user.findMany({ where: { yosh: { gt: 18 } }, include: { orders: true } });   // (2.11, 2.12)
await prisma.user.update({ where: { id }, data: {...} });   // U
await prisma.user.delete({ where: { id } });           // D
await prisma.$transaction(async (tx) => {...});        // tranzaksiya (2.14)
bash
npx prisma migrate dev --name x   # migrate (2.7)
npx prisma generate                # client (2.8)
npx prisma studio                  # GUI (2.15)

4. Batafsil kod namunalari

Misol 1 — To'liq schema (2.4-2.6)

prisma
// prisma/schema.prisma
generator client { provider = "prisma-client-js" }
datasource db { provider = "postgresql"; url = env("DATABASE_URL") }

model User {
  id        Int      @id @default(autoincrement())
  ism       String
  email     String   @unique
  parol     String                                     // hash (5.15)
  rol       Role     @default(USER)
  orders    Order[]                                    // one-to-many (2.6)
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  @@map("users")
}

model Order {
  id        Int         @id @default(autoincrement())
  user      User        @relation(fields: [userId], references: [id], onDelete: Cascade)   // FK (6.6: 2.7)
  userId    Int
  summa     Decimal     @db.Decimal(10, 2)
  holat     OrderStatus @default(YANGI)
  items     OrderItem[]
  createdAt DateTime    @default(now())
  @@index([userId])                                    // indeks (6.10)
  @@map("orders")
}

model Product {
  id        Int         @id @default(autoincrement())
  nom       String
  narx      Decimal     @db.Decimal(10, 2)
  zaxira    Int         @default(0)
  items     OrderItem[]
  @@map("products")
}

model OrderItem {                                       // many-to-many junction (qo'lda — qo'shimcha maydon bilan)
  order     Order   @relation(fields: [orderId], references: [id])
  orderId   Int
  product   Product @relation(fields: [productId], references: [id])
  productId Int
  miqdor    Int
  narx      Decimal @db.Decimal(10, 2)                  // snapshot (6.3: Misol 7)
  @@id([orderId, productId])                            // composite PK
  @@map("order_items")
}

enum Role { USER ADMIN }
enum OrderStatus { YANGI TASDIQLANDI YETKAZILDI BEKOR }

Misol 2 — Client singleton (2.10)

js
// lib/prisma.js
import { PrismaClient } from "@prisma/client";
import { config } from "../config/index.js";

const globalForPrisma = globalThis;
export const prisma =
  globalForPrisma.prisma ||
  new PrismaClient({
    log: config.isProd ? ["error"] : ["query", "warn", "error"],   // dev'da SQL log (2.16)
  });
if (!config.isProd) globalForPrisma.prisma = prisma;               // hot-reload (2.10)

Misol 3 — CRUD service (type-safe — 2.9, 2.11)

js
import { prisma } from "../lib/prisma.js";

export const UserService = {
  yarat: (data) => prisma.user.create({
    data,
    select: { id: true, ism: true, email: true, rol: true },       // parolsiz (2.18)
  }),

  topId: (id) => prisma.user.findUnique({
    where: { id }, select: { id: true, ism: true, email: true },   // parolsiz
  }),

  emailTop: (email) => prisma.user.findUnique({ where: { email } }), // parol bilan (login — 5.15)

  royxat: ({ page = 1, limit = 20, qidiruv, rol }) => prisma.user.findMany({
    where: {
      ...(rol && { rol }),
      ...(qidiruv && { ism: { contains: qidiruv, mode: "insensitive" } }),   // qidiruv (2.11)
    },
    select: { id: true, ism: true, email: true, rol: true },
    take: limit, skip: (page - 1) * limit,                          // sahifalash (2.11)
    orderBy: { createdAt: "desc" },
  }),

  yangila: (id, data) => prisma.user.update({ where: { id }, data }),

  ochir: (id) => prisma.user.delete({ where: { id } }),
};

Misol 4 — Relations: include (eager — 2.12)

js
// Buyurtma + user + mahsulotlar (nested include — JOIN — 2.12)
export const buyurtmaToliq = (id) => prisma.order.findUnique({
  where: { id },
  include: {
    user: { select: { ism: true, email: true } },                  // user (kerakli)
    items: { include: { product: { select: { nom: true, narx: true } } } },   // ichma-ich
  },
});
// Natija TYPE-SAFE: order.user.ism, order.items[0].product.nom (autocompletion — 2.2)

// User + faqat tugallangan buyurtmalari (shartli include)
export const userFaol = (userId) => prisma.user.findUnique({
  where: { id: userId },
  include: { orders: { where: { holat: "TUGALLANDI" }, orderBy: { createdAt: "desc" } } },
});

Misol 5 — Nested write (bog'liq birga — 2.13)

js
// Ro'yxatdan o'tish + boshlang'ich profil BIRGA (nested — atomik — 2.13)
export const royxatdanOtish = (data) => prisma.user.create({
  data: {
    ism: data.ism, email: data.email, parol: data.parolHash,
    profile: {                                                     // bog'liq profil birga
      create: { bio: "", avatar: null },
    },
  },
  include: { profile: true },
});

// Buyurtma + items birga (nested — 2.13)
export const buyurtmaYarat = (userId, items) => prisma.order.create({
  data: {
    userId,
    summa: items.reduce((s, i) => s + i.narx * i.miqdor, 0),
    items: { create: items },                                      // items birga (bir tranzaksiya)
  },
  include: { items: true },
});

Misol 6 — Tranzaksiya (interactive — 2.14)

js
// Pul o'tkazish — interactive transaction (murakkab mantiq — 2.14, 6.9)
export async function pulOtkaz(fromId, toId, summa) {
  return prisma.$transaction(async (tx) => {                       // tx — tranzaksiya client
    // Yechish (atomik decrement — 6.9: 2.11)
    const from = await tx.account.update({
      where: { id: fromId },
      data: { balans: { decrement: summa } },
    });
    if (from.balans.lessThan(0)) {                                 // Decimal taqqoslash
      throw new Error("Balans yetarli emas");                      //  avtomatik ROLLBACK
    }
    // Qo'shish
    await tx.account.update({ where: { id: toId }, data: { balans: { increment: summa } } });
    // Log
    await tx.transfer.create({ data: { fromId, toId, summa } });
  });
  // xato  avtomatik rollback; muvaffaqiyat  commit (6.9: ACID)
}

Misol 7 — Zaxira (lock + tranzaksiya — 6.9: 2.13)

js
// Buyurtma + zaxira kamaytirish (atomik — 6.9)
export async function buyurtmaZaxira(userId, items) {
  return prisma.$transaction(async (tx) => {
    for (const item of items) {
      // Atomik: zaxira yetarli bo'lsa kamaytir (updateMany count bilan)
      const r = await tx.product.updateMany({
        where: { id: item.productId, zaxira: { gte: item.miqdor } },   // shart bilan
        data: { zaxira: { decrement: item.miqdor } },
      });
      if (r.count === 0) throw new Error("Zaxira yetarli emas");        //  rollback
    }
    return tx.order.create({
      data: { userId, items: { create: items }, summa: 0 },             // (summa hisoblanadi)
      include: { items: true },
    });
  });
}

Misol 8 — Express + xato boshqaruvi (5.6, 5.10)

js
import { Prisma } from "@prisma/client";
import { UserService } from "../services/userService.js";

export const userYarat = async (req, res, next) => {
  try {
    const user = await UserService.yarat(req.body);                // (validatsiya — 5.9)
    res.status(201).json({ success: true, data: user });           // (5.7)
  } catch (err) {
    if (err instanceof Prisma.PrismaClientKnownRequestError) {
      if (err.code === "P2002") {                                  // unique buzildi (2.18)
        return res.status(409).json({ error: "Email band" });      // (5.10)
      }
      if (err.code === "P2025") {                                  // topilmadi
        return res.status(404).json({ error: "Topilmadi" });
      }
    }
    next(err);
  }
};
// Prisma xato kodlari: P2002 (unique), P2025 (not found), P2003 (FK)

Misol 9 — Raw query (murakkab — 2.16)

js
// Murakkab so'rov (window — 6.7) — raw, lekin type-safe parametr (14)
const topMijozlar = await prisma.$queryRaw`
  SELECT u.ism, SUM(o.summa) AS jami,
    RANK() OVER (ORDER BY SUM(o.summa) DESC) AS reyting
  FROM users u JOIN orders o ON u.id = o."userId"
  WHERE o.holat = 'TUGALLANDI'
  GROUP BY u.id, u.ism
  LIMIT ${10}
`;
// $queryRaw — tagged template (parametrlar avtomatik xavfsiz — injection'siz — 14)

5. To'g'ri va noto'g'ri holatlar

1) Har joyda yangi PrismaClient

js
//  ko'p instance  ulanish tugaydi (2.10)
function handler() { const prisma = new PrismaClient(); ... }

//  singleton (bir marta — Misol 2)
import { prisma } from "../lib/prisma.js";

2) N+1 (include o'rniga tsikl)

js
//  N+1 (2.16)
for (const u of users) await prisma.order.findMany({ where: { userId: u.id } });

//  include
await prisma.user.findMany({ include: { orders: true } });

3) Parolni select'siz qaytarish

js
//  parol ham keladi (14, 2.18)
await prisma.user.findUnique({ where: { id } });

//  select (kerakli maydonlar)
await prisma.user.findUnique({ where: { id }, select: { id: true, email: true } });

4) Qo'lda schema o'zgartirish (migratesiz)

text
 DB'da qo'lda ALTER (schema bilan nomuvofiq — 2.7)
 schema.prisma o'zgartiring  migrate dev

5) Raw query string birlashtirish

js
//  injection (14, 2.16)
prisma.$queryRawUnsafe(`SELECT * FROM users WHERE email = '${email}'`);

//  tagged template / parametrli
prisma.$queryRaw`SELECT * FROM users WHERE email = ${email}`;

6. Keng tarqalgan xatolar va yechimlari

Xato 1 — PrismaClientInitializationError

Sababi: DATABASE_URL noto'g'ri, DB ishlamayapti, yoki generate qilinmagan (2.3, 2.8). Yechimi: .env tekshiring; DB ishga tushiring; prisma generate.

Xato 2 — P2002 Unique constraint failed

Sababi: unique buzildi (email — 2.4). Yechimi: 409 qaytaring (Misol 8); oldindan tekshiring.

Xato 3 — P2025 Record not found

Sababi: update/delete'da yo'q qator 2.9-bob. Yechimi: 404 qaytaring; oldindan findUnique.

Xato 4 — Type xatosi (so'rov)

Sababi: schema o'zgardi, generate qilinmagan 2.8-bob. Yechimi: prisma generate (client yangilash).

Xato 5 — Migration konflikti

Sababi: schema va migration nomuvofiq, yoki qo'lda o'zgarish 2.7-bob. Yechimi: migrate status; dev'da migrate reset (ehtiyot — ma'lumot o'chadi).

Xato 6 — N+1 (sekin)

Sababi: tsiklda alohida so'rov 2.16-bob. Yechimi: include; log: ["query"] bilan tekshiring.


7. Integratsiya — bu mavzu stack'ning qayerida uchraydi

  • SQL (6.4-6.10): Prisma SQL ustida; raw query.
  • PostgreSQL/MySQL (6.5, 6.6): Prisma provider.
  • Sequelize 6.11-bob: muqobil ORM (taqqoslash).
  • TypeScript (7): type-safety — Prisma kuchi.
  • Tranzaksiya/ACID 6.9-bob: $transaction.
  • Indeks/N+1 6.10-bob: include, @@index.
  • NestJS 8.3-bob: Prisma module.
  • Next.js (13): Prisma (singleton — 2.10).
  • Auth 5.15-bob: User model, parol.
  • Xavfsizlik (14): injection ($queryRaw parametrli).

8. Eng yaxshi amaliyotlar (best practices)

  • PrismaClient singleton (bir marta — 2.10).
  • Migration (migrate dev/deploy — qo'lda emas — 2.7, 14).
  • include o'ylab (N+1 oldini oling, ortiqcha emas — 2.12, 2.16).
  • select bilan kerakli maydonlar (maxfiy yashiring — parol — 2.11, 2.18).
  • Tranzaksiya ($transaction — ko'p yozuv; nested write — 2.13, 2.14).
  • Type-safety'dan foydalaning (autocompletion, kompilyatsiya xatosi — 2.2).
  • $queryRaw parametrli (tagged template — injection — 2.16, 14).
  • log: ["query"] (dev) — SQL ko'rish 2.16-bob.
  • Xatolarni kod bo'yicha (P2002 409 — Misol 8, 5.10).
  • Prisma Studio (dev — ma'lumot ko'rish — 2.15).

9. Amaliy loyiha: "Prisma bilan Type-Safe Backend"

Prisma'ni professional darajada mustahkamlash.

Maqsad

Prisma bilan to'liq, type-safe, migration-asosli backend qurish: schema, client, relations, nested write va tranzaksiya.

Talablar (requirements)

  1. Schema: User/Order/Product/OrderItem — relations, enum, indeks, @db turlar (Misol 1, 2.4-2.6).
  2. Migrate + generate: schema DB client (2.7, 2.8).
  3. Client singleton: lib/prisma.js (Misol 2, 2.10).
  4. CRUD service: type-safe; select (parolsiz); qidiruv/sahifalash (Misol 3, 2.11).
  5. Relations: include (nested, shartli — Misol 4, 2.12).
  6. Nested write: user+profil yoki order+items birga (Misol 5, 2.13).
  7. Tranzaksiya: pul o'tkazish / zaxira (interactive — Misol 6, 7, 2.14).
  8. Express: xato kodlari (P2002409 — Misol 8).
  9. Raw query: murakkab so'rov (window — parametrli — Misol 9, 2.16).
  10. Prisma Studio: ma'lumotni ko'rish 2.15-bob.

Maslahatlar (hint)

  • Singleton: globalThis (hot-reload — 2.10, 1-xato).
  • include: N+1 oldini oladi (2.12, 2.16).
  • select: parolsiz (2.18, 3-xato).
  • Tranzaksiya: $transaction(async tx => {}) 2.14-bob.
  • increment/decrement: atomik 6.9-bob.
  • $queryRaw: tagged template (injection — 2.16, 5-xato).
  • P2002 (unique), P2025 (not found) — Misol 8.

"Tayyor" mezonlari (acceptance criteria)

  • Schema (relations, enum, indeks).
  • Migrate + generate ishlaydi.
  • Client singleton.
  • CRUD type-safe (select — parolsiz).
  • include (nested, shartli).
  • Nested write (bog'liq birga).
  • Tranzaksiya ($transaction).
  • Xato kodlari (P2002409).
  • Raw query (parametrli).
  • N+1 yo'q (include).

Yechim kodi ataylab berilmagan — bu loyihani o'zingiz yozib ko'ring.


10. Xulosa va keyingi bobga ko'prik

Bu bobda zamonaviy, type-safe ORM — Prisma ni chuqur o'rgandik:

  • Prisma (schema + client + migrate — 2.1); type-safety (kompilyatsiya xatosi, autocompletion — 2.2).
  • Schema (schema.prisma — model/atribut/enum — 2.4, 2.5); relations (@relation, avtomatik m:n junction — 2.6); migrate (avtomatik — 2.7), generate (client — 2.8).
  • Client (findUnique/findMany/create — 2.9, type-safe; singleton — 2.10); operatorlar 2.11-bob; include (eager JOIN — 2.12).
  • Nested write (bog'liq birga — atomik — 2.13); tranzaksiya ($transaction — 2.14); Prisma Studio 2.15-bob; raw query 2.16-bob; taqqoslash 2.17-bob.

Keyingi bob — 6.13-bob: ORM — TypeORM (entity, repository, relations). Prisma (schema-first) ni bildik; endi uchinchi ORM — TypeORM ni o'rganamiz. TypeORM — class va dekorator asosida (Prisma'dan boshqacha), va NestJS (8) bilan eng tabiiy ishlaydi. Entity, repository pattern, relations — chuqur. Bu — NestJS qismiga (8) tayyorgarlik.


Foydalanilgan rasmiy/ishonchli manbalar

  • prisma.io/docs — Prisma Schema, Client, Migrate, Relations, Transactions, Best practices
  • prisma.io — Relation queries (include, nested write); Prisma 7 (2025 — TypeScript runtime)
  • tech-insider — Prisma ORM tutorial 2026 (type-safe API)

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
6.12-bob: ORM — Prisma (schema, migrate, client, relations) — Wisar