IlmHamroh
JavaScript Full-stack/30-qism. NestJS31/65-dars15 daqiqa
Mundarija (24)

Prisma bilan NestJS: PrismaService, lifecycle va Prisma xatolari filtri

Qisqacha: Nest hujjatidagi naqsh: PrismaService extends PrismaClient — Prisma klienti @Injectable xizmatga aylanadi. onModuleInit da $connect, onModuleDestroy da $disconnect; @Global PrismaModule uni hamma joyga beradi. Prisma 7 da klientga adapter (PrismaPg) beriladi. Prisma xatolarini HTTP'ga @Catch(Prisma.PrismaClientKnownRequestError) filtri aylantiradi: P2002 (takror) → 409, P2025 (topilmadi) → 404. vazifalar-api bu naqshni olmadi — ombor ish vaqtida tanlanadi va Prisma o'z pool'i bilan OmborModule ichida yashaydi.

Bu darsda

  • PrismaService va PrismaModule ni Prisma 7 adapteri bilan yozasiz.
  • onModuleInit / onModuleDestroy qachon ishlashini haqiqiy chiqishda ko'rasiz.
  • Prisma xato kodlarini HTTP status'ga aylantiruvchi exception filter yozasiz va adapter bilan meta.target nega null ekanini bilasiz.
  • Kanon nega PrismaService klassini kiritmaganini va o'rniga nima borligini tushuntirasiz.

Oldin bilishingiz kerak: Prisma 7: o'rnatish va arxitektura, Prisma prodakshnda, Lifecycle hook'lar, Exception filter'lar, So'rov konteksti: nestjs-cls.

O'tgan darsda config, log va so'rov konteksti qadami commit bo'ldi. Endi ma'lumot qatlami: 27-qismda o'rgangan ORM'lar Nest ichida qanday ulanadi. Bu va keyingi uch dars — tajriba darslari: har birida Nest naqshi, kanon tajribasining haqiqiy natijasi va nega loyiha boshqa yo'lni tanlagani.

1. Nega bu kerak?

27-qismda Prisma 7 bilan PrismaOmbori ni yozgandik (Prisma 7). U yerda klient bitta joyda yaratilardi va ilova yopilganda $disconnect qilinardi — buni server.ts qo'lda boshqarardi.

Nest'da ikki savol paydo bo'ladi. Birinchisi: klient bitta bo'lishi va kerakli xizmatlarga DI orqali yetishi kerak. Ikkinchisi: ulanish ilova ko'tarilganda ochilib, yopilganda yopilishi kerak — main.ts ga qo'l bilan yozmasdan.

O'xshatish: ofisdagi bitta printer. Har xodimga alohida printer olmaysiz — bitta, umumiy, hamma ulanadi. Ertalab birinchi kelgan uni yoqadi, kechqurun oxirgi ketgan o'chiradi. Nest'da "yoqish" va "o'chirish" ni lifecycle hook'lar qiladi (Lifecycle hook'lar).

2. PrismaService naqshi

2.1 Xizmat — klientning o'zi

Nest hujjatidagi yo'l — Prisma klientidan meros olish:

ts
const URL = "postgres://postgres@127.0.0.1:5495/tajriba30";

@Injectable()
class PrismaService extends PrismaClient
  implements OnModuleInit, OnModuleDestroy {
  constructor() {
    super({ adapter: new PrismaPg({ connectionString: URL }) });
  }
  async onModuleInit() {
    const t = performance.now();
    await this.$connect();
    const ms = (performance.now() - t).toFixed(0);
    console.log(`  onModuleInit: $connect ${ms} ms`);
  }
  async onModuleDestroy() {
    await this.$disconnect();
    console.log("  onModuleDestroy: $disconnect");
  }
}

@Global()
@Module({ providers: [PrismaService], exports: [PrismaService] })
class PrismaModule {}

Bu kanon tajribasining kodi (telefon uchun bo'lindi, ma'no o'zgarmagan). Qatorma-qator:

  • extends PrismaClient — PrismaService nusxasi to'liq Prisma klienti: this.foydalanuvchi.create(...), this.$transaction(...) — hammasi bor. Ustiga @Injectable() qo'shildi — Nest uni yaratadi va kerakli joyga beradi.
  • super({ adapter: ... }) — Prisma 7 da klient bazaga o'zi ulanmaydi: unga driver adapter beriladi. PrismaPg — pg drayveri ustidagi adapter (Prisma 7). Prisma 6 dagi Nest hujjati misollarida adapter yo'q — eski kodda shunday uchratasiz.
  • onModuleInit — modul tayyor bo'lgach, ilova so'rov qabul qilishidan oldin. $connect shu yerda — birinchi so'rov ulanish ochilishini kutmasin.
  • onModuleDestroy — app.close() da. $disconnect — ulanishlar yopiladi, jarayon toza chiqadi.
  • @Global() modul — PrismaService ni har modul import qilmasdan oladi (Modullar).

Diqqat: PrismaService ni ikki modulning providers iga yozmang. Modullar darsidagi tuzoq: ikki nusxa — ikki ulanishlar hovuzi (pool). Bazaning max_connections chegarasi ikki barobar tez to'ladi.

2.2 Filtr: Prisma xatosi → HTTP

Prisma xatolari kod bilan keladi: P2002 — noyoblik cheklovi buzildi, P2025 — kerakli yozuv topilmadi (Prisma: CRUD). Ularni har controller'da try/catch qilish o'rniga — bitta exception filter:

ts
@Catch(Prisma.PrismaClientKnownRequestError)
class PrismaXatoFiltri implements ExceptionFilter {
  catch(
    x: Prisma.PrismaClientKnownRequestError,
    host: ArgumentsHost,
  ) {
    const holat =
      x.code === "P2002" ? 409 : x.code === "P2025" ? 404 : 500;
    host.switchToHttp().getResponse<Response>().status(holat).json({
      status: holat, kod: x.code, maydon: x.meta?.["target"] ?? null,
    });
  }
}

@Catch(Klass) — filtr faqat shu turdagi xatoni ushlaydi; qolganlari keyingi filtrga (yoki Nest'ning sukutiga) o'tadi. x.meta?.["target"] — hujjatga ko'ra P2002 da buzilgan maydon nomi.

2.3 Controller va ulash

ts
@Controller("f")
class C {
  constructor(private readonly db: PrismaService) {}
  @Post("takror") takror() {
    return this.db.foydalanuvchi.create({
      data: { email: "aziz@example.com", toliqIsm: "Takror" },
    });
  }
  @Get(":id") ol(@Param("id") id: string) {
    return this.db.foydalanuvchi.findUniqueOrThrow({
      where: { id: BigInt(id) }, select: { email: true },
    });
  }
}

@Module({
  imports: [PrismaModule],
  controllers: [C],
  providers: [{ provide: APP_FILTER, useClass: PrismaXatoFiltri }],
})
class M {}

foydalanuvchi — 27-qism sxemasidagi Foydalanuvchi modeli; namuna bazasida aziz@example.com allaqachon bor. BigInt(id) — sxemada id BigInt (Prisma: modellar). Filtr global — APP_FILTER bilan, DI orqali (Global enhancer'lar).

2.4 Natija

Tajriba uch so'rov yubordi: takror email bilan yaratish, mavjud foydalanuvchi va yo'q foydalanuvchi. Kanon chiqishi (kanon o'lchovi, IlmHamroh, 2026-10, NestJS 12.2.0, Prisma 7.10.1):

text
  onModuleInit: $connect 53 ms
POST /f/takror → 409 {"status":409,"kod":"P2002","maydon":null}
GET /f/1 → 200 {"email":"aziz@example.com"}
GET /f/999999 → 404 {"status":404,"kod":"P2025","maydon":null}
  onModuleDestroy: $disconnect
  • Birinchi qator — onModuleInit so'rovlardan oldin: ulanish 53 ms. Bu vaqtni birinchi foydalanuvchi to'lamaydi.
  • P2002 → 409, P2025 → 404 — filtr ishladi.
  • "maydon": null — topilma. Hujjatda meta.target maydon nomini beradi (["email"]). Driver adapter bilan esa u null: ma'lumot boshqa joyda — meta.driverAdapterError.cause ichida. 27-qismda PrismaOmbori aynan shu sababli xato sababini driverAdapterError dan o'qiydi (Prisma: nested write va tranzaksiyalar).
  • Oxirgi qator — app.close() da $disconnect.

Tekshirib ko'ring: Filtr @Catch(Prisma.PrismaClientKnownRequestError) bilan yozilgan. Baza butunlay o'chiq bo'lsa, so'rov qanday javob oladi?

Javob

Bu filtr ushlamaydi: ulanish xatosi PrismaClientKnownRequestError emas (boshqa klass — masalan, PrismaClientInitializationError). Xato keyingi filtrga — vazifalar-api da Problem Details filtriga — o'tadi va 500 bo'ladi. To'g'ri: baza yo'qligi — mijozning aybi emas. Ehtiyot: onModuleInit dagi $connect bo'lsa, ilova umuman ishga tushmagan bo'lardi — fail-fast.

3. Lifecycle — qachon nima

sequenceDiagram
  participant M as main.ts
  participant N as Nest
  participant P as PrismaService
  participant DB as Postgres
  M->>N: NestFactory.create
  N->>P: constructor (adapter)
  N->>P: onModuleInit
  P->>DB: $connect (53 ms)
  M->>N: listen
  Note over N,DB: so'rovlar
  M->>N: app.close()
  N->>P: onModuleDestroy
  P->>DB: $disconnect

Diagrammadagi tartib Lifecycle hook'lar darsidagi bilan bir xil: onModuleInit — listen dan oldin, onModuleDestroy — close da. Signal kelganda (SIGTERM) app.close() ni kim chaqiradi? Nest hujjati app.enableShutdownHooks() ni taklif qiladi. Kanon uni ishlatmaydi: signalni jarayon.ts o'zi ushlaydi — avval HTTP ulanishlarni to'g'ri yopadi, keyin app.close(). Ikki joyda ushlansa, yopish ikki marta boshlanardi (main.ts dagi izoh).

4. Kanon qarori: PrismaService yo'q

4.1 Loyihada nima bor

vazifalar-api da Prisma — to'rt saqlash usulidan biri: SAQLASH=xotira | fayl | postgres | prisma (postgres va prisma ustiga — ixtiyoriy Redis kesh, REDIS_URL). Qaysi biri — config hal qiladi, ish vaqtida. Bu Dynamic modullar darsida qurilgan OmborModule.forRootAsync():

ts
static forRootAsync(): DynamicModule {
  return {
    module: OmborModule,
    providers: [
      {
        provide: SAQLASH,
        useFactory: (config: Config, log: Log): Promise<Saqlash> =>
          omborYarat(config, log),
        inject: [CONFIG, LOG],
      },
      {
        provide: VAZIFA_OMBORI,
        useFactory: (s: Saqlash) => s.ombor,
        inject: [SAQLASH],
      },
      SaqlashYopuvchi,
    ],
    exports: [VAZIFA_OMBORI],
  };
}

omborYarat — 27-qismdan qolgan funksiya. SAQLASH=prisma bo'lsa, u pool'ni o'zi yaratadi va adapter'ga beradi:

ts
const pool = new pg.Pool({
  connectionString: config.DATABASE_URL,
  application_name: "vazifalar-api",
  max: config.PG_POOL_MAX,
  idleTimeoutMillis: 30_000,
  connectionTimeoutMillis: 5_000,
  statement_timeout: config.PG_STATEMENT_TIMEOUT,
});
const db = new PrismaClient({ adapter: new PrismaPg(pool) });

Yopish — SaqlashYopuvchi ning onApplicationShutdown hook'ida: HTTP server yopilgandan keyin, boshlangan so'rovlar bazani ishlatib bo'lgach.

4.2 Nega shunday

Hujjat naqshi Kanon
Ombor tanlash doim Prisma config bo'yicha 4 variant (+ kesh)
Pool adapter o'zi o'zimiz: timeout'lar, application_name
Xato kodlari global filtr PrismaOmbori ichida → KonfliktXatosi
Xizmat nima ko'radi butun PrismaClient VazifaOmbori interfeysi
  • Ombor tanlanadi. PrismaService doim Prisma. Kanonda esa xuddi shu xizmat va controller'lar xotira, fayl, pg va Prisma bilan ishlaydi — bitta shartnoma testlari to'plami bilan (27-qism).
  • Pool nazoratda. Prisma o'z pool'ini yaratsa, statement_timeout, application_name va error tinglovchisini qo'yish qiyinroq. 26-qismda o'rgangan sozlamalar (Connection pooling) yo'qolmasin.
  • Xatolar domenda. P2002 ni global filtr 409 qilsa, xato javobi Prisma tilida gapiradi (kod: "P2002"). Kanonda PrismaOmbori uni KonfliktXatosi ga aylantiradi — xuddi pg omboridagi 23505 kabi — va javob Problem Details: "type": ".../takror-matn". Mijoz qaysi ORM ishlatilganini bilmaydi.
  • Turlar chiqmaydi. extends PrismaClient — xizmatga butun klient beriladi: istalgan jadvalga, istalgan $queryRaw. Bu Repository naqshi darsining mavzusi.

Nima yo'qotdik: Nest hujjatini o'qib kelgan dasturchi PrismaService ni qidiradi va topmaydi. O'rniga — OmborModule va uning boshidagi izoh.

4.3 Farq xizmat ichida qanday ko'rinadi

Ikki yondashuvning farqi eng aniq xizmat constructor'ida ko'rinadi. Hujjat naqshida xizmat Prisma'ni to'g'ridan oladi:

ts
// Hujjat naqshi: xizmat Prisma klientini biladi
@Injectable()
export class VazifalarService {
  constructor(private readonly db: PrismaService) {}
  ol(id: number) {
    return this.db.vazifa.findUniqueOrThrow({
      where: { id: BigInt(id) },
    });
  }
}

Kanonda xizmat faqat interfeysni oladi — uning ortida qaysi ombor turgani unga noma'lum:

ts
// Kanon: xizmat VazifaOmbori interfeysini biladi, xolos
@Injectable()
export class VazifalarService {
  constructor(
    @Inject(VAZIFA_OMBORI) private readonly ombor: VazifaOmbori,
  ) {}
  async ol(id: number): Promise<Vazifa> {
    const v = await this.ombor.ol(id);
    if (!v) throw topilmadi(id);
    return v;
  }
}

(Ikkinchisi — kanon vazifalar.service.ts dan ol metodi; constructor'dagi LOG va XABARCHI tushirib qoldirildi. Birinchisi — taqqoslash uchun sxema.) Birinchisida BigInt, findUniqueOrThrow va P2025 — xizmatning muammosi. Ikkinchisida ular PrismaOmbori ichida qoladi, xizmat esa xotira omborida ham, pg omborida ham aynan bir xil ishlaydi. Interfeys ortidagi @Inject(TOKEN) — Custom provider'lar darsidagi naqsh.

4.4 O'z loyihangiz uchun: qaysi birini tanlash

Loyihangizda Tanlov Sabab
Prisma yagona baza vositasi, almashtirish rejasi yo'q hujjat naqshi (PrismaService) sodda, hamma Nest dasturchisiga tanish
Bir nechta saqlash usuli yoki testda xotira ombori kerak ombor interfeysi + fabrika xizmat ORM'ga bog'lanmaydi
Prisma bor, lekin pool sozlamalari muhim PrismaService + o'z pg.Pool adapterga timeout va application_name qo'lingizda

Uchinchi qator — oraliq yo'l: PrismaService ning constructor'ida new PrismaPg({ connectionString }) o'rniga o'zingiz yaratgan pg.Pool ni bering. Naqsh hujjatdagidek qoladi, pool esa nazoratingizda.

5. Express'da qanday edi, Nest'da qanday

27-qism (Express) Nest
Klient kim yaratadi omborYarat (server.ts dan) DI: provider yoki fabrika
Kimga yetadi parametr bilan constructor orqali
Ochish / yopish server.ts qo'lda lifecycle hook'lar
Xato → HTTP xato ishlovchi middleware exception filter

Kanonda chap ustundagi omborYarat o'zgarmadi — u Nest fabrikasi ichiga ko'chdi. O'zgargani — "kim chaqiradi" va "kim yopadi": endi Nest. 27-qismdagi server.ts qilgan ish (yaratish, EGASI_ID tekshiruvi, yopish) bir qatorga ham kamaymadi, faqat OmborModule ga joylashdi. Nest'ga ko'chishning umumiy narxi ham shu yerda ko'rinadi. Kanon o'lchovida sovuq start Express'dagi 2.5 s dan 4.8–5.3 s ga oshdi (bitta mashina, bir vaqtda o'lchangan, nisbat muhim). Bazali PATCH so'rovlari tezligi esa farqsiz qoldi — vaqtning asosiy qismi bazada.

6. Hujumchi nigohi

PrismaService extends PrismaClient xizmatga butun klientni beradi — shu jumladan xom SQL metodlarini. 27-qismda ularni ko'rgandik (Prisma: raw SQL va TypedSQL):

ts
// ✅ teg-shablon: qiymat parametr bo'lib ketadi ($1)
await this.db.$queryRaw`SELECT * FROM vazifalar WHERE matn = ${matn}`;
// ❌ satr birlashtirish: SQL injection
await this.db.$queryRawUnsafe(
  "SELECT * FROM vazifalar WHERE matn = '" + matn + "'",
);

Hujumchi matn ga x' OR '1'='1 yuborsa, ikkinchi so'rov hamma vazifalarni qaytaradi — boshqa foydalanuvchilarnikini ham. PrismaService hamma xizmatga ochiq bo'lgani uchun xavfli metod ham hamma joyda bor. Himoya: $queryRawUnsafe ni lint qoidasi bilan taqiqlash va xom SQL'ni faqat ombor qatlamida yozish. Kanonda xizmatlar PrismaClient ni umuman ko'rmaydi — xom SQL faqat PrismaOmbori va PgOmbori ichida, parametrli.

7. Ko'p uchraydigan xatolar

Belgi Sabab Davosi
Prisma 7 da klient yaratishda xato adapter berilmagan new PrismaClient({ adapter: new PrismaPg(...) })
Ulanishlar soni ikki barobar PrismaService ikki modul providers ida bitta @Global modul
Jarayon yopilmaydi $disconnect yo'q onModuleDestroy yoki onApplicationShutdown
meta.target — null driver adapter meta.driverAdapterError.cause dan o'qing
P2025 — 500 filtr yo'q yoki @Catch boshqa klass @Catch(Prisma.PrismaClientKnownRequestError)
Birinchi so'rov sekin $connect yo'q — dangasa ulanish onModuleInit da $connect

8. Mashqlar

Mashqlar kurs/mashqlar/30/31-prisma-nestjs/ da.

1-mashq (oson): hook va kod

To'ldiring:

  • Ulanishni ochadigan hook —
  • Takror qiymat (noyoblik) Prisma kodi —
  • findUniqueOrThrow topa olmasa —
  • Prisma 7 da pg uchun adapter klassi —
Yechim
  • onModuleInit — listen dan oldin ishlaydi.
  • P2002 → 409, P2025 → 404.
  • PrismaPg — @prisma/adapter-pg paketidan.

2-mashq (o'rta): xato kodini Problem Details'ga aylantirish

prismaXatosi(x, yol) funksiyasini yozing. x — { code, meta } obyekt. Natija — Problem Details: P2002 → 409, title: "Takror qiymat"; P2025 → 404, title: "Topilmadi"; boshqasi → 500, title: "Ichki xato". Maydon nomi meta.target dan, u null bo'lsa — meta.driverAdapterError.cause.constraint.fields dan (bo'lmasa null). Ishora: undefined va null darsidagi ?. va ??.

Yechim
js
const JADVAL = {
  P2002: { status: 409, title: "Takror qiymat" },
  P2025: { status: 404, title: "Topilmadi" },
};

function prismaXatosi(x, yol) {
  const { status, title } =
    JADVAL[x.code] ?? { status: 500, title: "Ichki xato" };
  const maydon = x.meta?.target
    ?? x.meta?.driverAdapterError?.cause?.constraint?.fields
    ?? null;
  return { status, title, instance: yol, kod: x.code, maydon };
}

console.log(prismaXatosi(
  { code: "P2002", meta: { target: ["email"] } }, "/f/takror"));
console.log(prismaXatosi({
  code: "P2002",
  meta: {
    target: null,
    driverAdapterError: {
      cause: { constraint: { fields: ["email"] } },
    },
  },
}, "/f/takror"));
console.log(prismaXatosi({ code: "P2025" }, "/f/999999"));
console.log(prismaXatosi({ code: "P1001" }, "/f/1").status);

Konsolda:

text
{
  status: 409,
  title: 'Takror qiymat',
  instance: '/f/takror',
  kod: 'P2002',
  maydon: [ 'email' ]
}
{
  status: 409,
  title: 'Takror qiymat',
  instance: '/f/takror',
  kod: 'P2002',
  maydon: [ 'email' ]
}
{
  status: 404,
  title: 'Topilmadi',
  instance: '/f/999999',
  kod: 'P2025',
  maydon: null
}
500

Ikkinchi chaqiruv — adapter holati: target null, maydon ichkaridan topildi. Ichki tuzilma (cause.constraint.fields) — model uchun soddalashtirilgan; real Prisma xatosida aniq yo'lni console.dir(x.meta, { depth: 5 }) bilan tekshiring. To'rtinchisi — P1001 (bazaga ulanib bo'lmadi) jadvalda yo'q, 500 bo'ldi.

3-mashq (qiyin): lifecycle tartibi

Provider'lar ro'yxati berilgan: { nom, kerak: [...], init?, destroy? }. ishgaTushir(royxat) provider'larni bog'liqlik tartibida yaratsin (avval kerak dagilar) va har biri uchun init ni chaqirsin; yop(tartib) — destroy larni teskari tartibda. Har qadamni konsolga yozing. Sinov: PrismaService (init — $connect, destroy — $disconnect), VazifalarOmbori (kerak: Prisma), VazifalarXizmati (kerak: ombor). Ishora: rekursiv funksiya va Set (Rekursiya).

Yechim
js
function ishgaTushir(royxat) {
  const nomli = new Map(royxat.map((p) => [p.nom, p]));
  const tayyor = new Set();
  const tartib = [];
  function yarat(nom) {
    if (tayyor.has(nom)) return;
    const p = nomli.get(nom);
    for (const k of p.kerak) yarat(k);
    console.log(`yaratildi: ${nom}`);
    tayyor.add(nom);
    tartib.push(p);
  }
  royxat.forEach((p) => yarat(p.nom));
  for (const p of tartib) p.init?.();
  return tartib;
}

function yop(tartib) {
  for (const p of [...tartib].reverse()) p.destroy?.();
}

const royxat = [
  { nom: "VazifalarXizmati", kerak: ["VazifalarOmbori"] },
  { nom: "VazifalarOmbori", kerak: ["PrismaService"] },
  {
    nom: "PrismaService",
    kerak: [],
    init: () => console.log("onModuleInit: $connect"),
    destroy: () => console.log("onModuleDestroy: $disconnect"),
  },
];

const tartib = ishgaTushir(royxat);
console.log("— so'rovlar —");
yop(tartib);

Konsolda:

text
yaratildi: PrismaService
yaratildi: VazifalarOmbori
yaratildi: VazifalarXizmati
onModuleInit: $connect
— so'rovlar —
onModuleDestroy: $disconnect

Ro'yxatda VazifalarXizmati birinchi, lekin PrismaService birinchi yaratildi — DI bog'liqliklarni oldin quradi (DI va IoC konteyner). Hook'lar hammasi yaratilgandan keyin chaqiriladi. Yopish teskari: avval undan foydalanuvchilar, keyin bazaning o'zi. Haqiqiy Nest'da onModuleDestroy ham modullar tartibiga bog'liq — model buni soddalashtirgan.

9. Loyiha qadami: o'zgarish yo'q — va nega

Bu darsda vazifalar-api o'zgarmaydi. Kanon PrismaService naqshini alohida tajribada sinadi (yuqoridagi chiqish) va loyihaga kiritmadi — «Kanon qarori» bo'limidagi to'rt sabab bilan.

O'z loyihangizda tekshirib ko'ring: SAQLASH=prisma bilan ishga tushirsangiz, OmborModule.forRootAsync Prisma klientini yaratadi, EGASI_ID ni bazada tekshiradi (fail-fast) va migratsiya holatini solishtiradi. Yopilganda logda "ombor ulanishlari yopildi" qatori chiqadi. Bularning hammasi Dynamic modullar darsidan beri bor; bu dars ularni hujjatdagi naqsh bilan solishtirish imkonini berdi.

Agar boshqa loyihada Prisma yagona saqlash bo'lsa va boshqa omborga o'tish rejada bo'lmasa — hujjat naqshi to'liq o'rinli. Kanon tanlovi — "noto'g'ri naqsh" emas, ko'p omborli loyihaga mos javob.

10. Real ishda

  • PrismaService extends PrismaClient — Nest + Prisma loyihalarining 90 % ida shunday (prisma.service.ts). Uni birinchi kunning o'zida uchratasiz.
  • Prisma 6 → 7 ko'chishi — eski PrismaService larda adapter yo'q va $on("beforeExit") kabi eskirgan kod bor. Yangilashda birinchi o'zgaradigan fayl.
  • Xato kodlari filtri — P2002 → 409 qoidasi ko'p loyihada global; javobda ichki kod (P2002) chiqib ketmasligi review'da tekshiriladi.
  • Intervyu: "Nest'da Prisma'ni qanday ulaysiz?", "ulanish qachon ochiladi va yopiladi?", "P2002 ni qanday ushlaysiz?".

Xulosa

  • Hujjat naqshi: PrismaService extends PrismaClient + @Injectable, @Global PrismaModule.
  • Prisma 7 — klientga adapter (PrismaPg) beriladi; eski misollarda yo'q.
  • onModuleInit — $connect (listen dan oldin), onModuleDestroy — $disconnect (close da).
  • @Catch(Prisma.PrismaClientKnownRequestError) filtri: P2002 → 409, P2025 → 404; adapter bilan meta.target — null.
  • Kanon: Prisma — OmborModule ichida, o'z pool'i bilan, xatolar PrismaOmbori da domen xatosiga aylanadi; xizmat faqat VazifaOmbori ni ko'radi.

Keyingi dars: TypeORM bilan NestJS — rasmiy @nestjs/typeorm moduli: forRootAsync, forFeature va @InjectRepository.

Manbalar

Ulashish:Telegram'da

Izohlar (0)

Izoh yozish uchun kiring.

  • Hozircha izoh yo'q. Birinchi bo'ling!
Prisma bilan NestJS: PrismaService, lifecycle va Prisma xatolari filtri — IlmHamroh