Prisma
Prisma - bu Node.js va TypeScript uchun open-source ORM. U oddiy SQL yozish yoki SQL query builder'lar (knex.js kabi) yoxud ORM'lar (TypeORM va Sequelize kabi) singari boshqa datab
Prisma - bu Node.js va TypeScript uchun open-source ORM. U oddiy SQL yozish yoki SQL query builder'lar (knex.js kabi) yoxud ORM'lar (TypeORM va Sequelize kabi) singari boshqa database access vositalaridan foydalanishga muqobil sifatida ishlatiladi. Prisma hozirda PostgreSQL, MySQL, SQL Server, SQLite, MongoDB va CockroachDB'ni qo'llab-quvvatlaydi (Preview).
Prisma'ni oddiy JavaScript bilan ham ishlatish mumkin, ammo u TypeScript'ni faol qo'llab-quvvatlaydi va TypeScript ekotizimidagi boshqa ORM'larga qaraganda yuqoriroq type-safety beradi. Prisma va TypeORM'ning type-safety kafolatlari bo'yicha batafsil taqqoslashni bu yerda topishingiz mumkin.
Prisma qanday ishlashini tezda tushunib olmoqchi bo'lsangiz, Quickstart ni kuzating yoki documentation ichidagi Introduction ni o'qing. Shuningdek, prisma-examples repository'sida REST va GraphQL uchun tayyor ishlaydigan misollar ham mavjud.
Boshlash
Ushbu recipe'da NestJS va Prisma bilan noldan qanday boshlashni o'rganasiz. Siz database'dan ma'lumot o'qiydigan va yozadigan REST API'ga ega namuna NestJS ilovasini qurasiz.
Ushbu qo'llanma uchun database server sozlash yukidan qochish maqsadida SQLite ishlatiladi. Agar siz PostgreSQL yoki MySQL ishlatayotgan bo'lsangiz ham bu qo'llanmadan foydalanishingiz mumkin - kerakli joylarda ularga oid qo'shimcha ko'rsatmalar beriladi.
Agar sizda allaqachon loyiha bo'lsa va Prisma'ga o'tishni o'ylayotgan bo'lsangiz, mavjud loyihaga Prisma qo'shish bo'yicha qo'llanmadan foydalaning. Agar TypeORM'dan ko'chayotgan bo'lsangiz, Migrating from TypeORM to Prisma qo'llanmasini o'qing.
NestJS loyihasini yaratish
Boshlash uchun NestJS CLI'ni o'rnating va quyidagi buyruqlar bilan ilova skeleton'ini yarating:
1$ npm install -g @nestjs/cli
2$ nest new hello-prismaFirst steps sahifasini ko'rib, ushbu buyruq yaratgan loyiha fayllari haqida ko'proq bilib oling. Shuningdek, endi ilovani ishga tushirish uchun npm start ni ishlatishingiz mumkin. Hozir http://localhost:3000/ da ishlayotgan REST API faqat src/app.controller.ts ichida yozilgan bitta route'ga ega. Ushbu qo'llanma davomida siz users va posts haqidagi ma'lumotlarni saqlash va olish uchun qo'shimcha route'lar yaratib borasiz.
Prisma'ni sozlash
Avval Prisma CLI'ni loyiha ichiga development dependency sifatida o'rnating:
1$ cd hello-prisma
2$ npm install prisma --save-devKeyingi qadamlar davomida Prisma CLI dan foydalanamiz. Best practice sifatida CLI'ni lokal ishlatish uchun oldiga npx qo'yish tavsiya etiladi:
1$ npx prismaExpand if you're using Yarn
Agar Yarn ishlatayotgan bo'lsangiz, Prisma CLI'ni quyidagicha o'rnatishingiz mumkin:
1$ yarn add prisma --devO'rnatilgach, uni yarn prefiksi bilan chaqirishingiz mumkin:
1$ yarn prismaEndi Prisma CLI'dagi init buyrug'i yordamida boshlang'ich Prisma setup'ni yarating:
1$ npx prisma initBu buyruq quyidagi tarkibga ega yangi prisma katalogini yaratadi:
schema.prisma: Database ulanishini ko'rsatadi va database schema'ni o'z ichiga oladiprisma.config.ts: Loyihangiz uchun konfiguratsiya fayli.env: Odatda database credential'larini environment variable'lar ko'rinishida saqlash uchun ishlatiladigan dotenv fayli
Generator output path'ni belgilash
Generated Prisma client uchun output path ni prisma init vaqtida --output ../src/generated/prisma orqali yoki to'g'ridan-to'g'ri Prisma schema ichida belgilang:
1generator client {
2 provider = "prisma-client"
3 output = "../src/generated/prisma"
4}Modul formatini sozlash
Generator ichida moduleFormat ni cjs ga o'rnating:
1generator client {
2 provider = "prisma-client"
3 output = "../src/generated/prisma"
4 moduleFormat = "cjs"
5}moduleFormat konfiguratsiyasi kerak, chunki Prisma v7 standart holatda ES module sifatida keladi va bu NestJS'ning CommonJS setup'i bilan mos kelmaydi. moduleFormat ni cjs ga o'rnatish Prisma'ni ESM o'rniga CommonJS modul generatsiya qilishga majbur qiladi.
Database ulanishini sozlash
Database ulanishi schema.prisma faylidagi datasource blokida sozlanadi. Standart holatda u postgresql ga o'rnatilgan bo'ladi, ammo bu qo'llanmada SQLite ishlatilgani uchun datasource blokidagi provider ni sqlite ga o'zgartirishingiz kerak:
1datasource db {
2 provider = "sqlite"
3}
4
5generator client {
6 provider = "prisma-client"
7 output = "../src/generated/prisma"
8 moduleFormat = "cjs"
9}Endi .env faylini oching va DATABASE_URL environment variable'ini quyidagicha o'zgartiring:
1DATABASE_URL="file:./dev.db"ConfigModule sozlanganiga ishonch hosil qiling, aks holda DATABASE_URL o'zgaruvchisi .env dan olinmaydi.
SQLite database'lari oddiy fayllar bo'ladi; undan foydalanish uchun alohida server kerak emas. Shu sabab host va port bilan connection URL yozish o'rniga, bu yerda dev.db deb nomlangan lokal faylga ishora qilishingiz kifoya. Bu fayl keyingi qadamda yaratiladi.
Expand if you're using PostgreSQL, MySQL, MsSQL or Azure SQL
PostgreSQL va MySQL bilan connection URL'ni database server ga ishora qiladigan qilib sozlashingiz kerak. Kerakli connection URL formati haqida bu yerda ko'proq bilishingiz mumkin.
PostgreSQL
Agar PostgreSQL ishlatayotgan bo'lsangiz, schema.prisma va .env fayllarini quyidagicha o'zgartiring:
schema.prisma
1datasource db {
2 provider = "postgresql"
3}
4
5generator client {
6 provider = "prisma-client"
7 output = "../src/generated/prisma"
8 moduleFormat = "cjs"
9}.env
1DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=SCHEMA"Barcha katta harflarda yozilgan placeholder'larni o'zingizning database credential'laringiz bilan almashtiring. Agar SCHEMA uchun nima yozishni bilmasangiz, ko'p hollarda standart qiymat public bo'ladi:
1DATABASE_URL="postgresql://USER:PASSWORD@HOST:PORT/DATABASE?schema=public"PostgreSQL database'ni qanday sozlashni bilmoqchi bo'lsangiz, Heroku'da bepul PostgreSQL database sozlash qo'llanmasini kuzatishingiz mumkin.
MySQL
Agar MySQL ishlatayotgan bo'lsangiz, schema.prisma va .env fayllarini quyidagicha o'zgartiring:
schema.prisma
1datasource db {
2 provider = "mysql"
3}
4
5generator client {
6 provider = "prisma-client"
7 output = "../src/generated/prisma"
8 moduleFormat = "cjs"
9}.env
1DATABASE_URL="mysql://USER:PASSWORD@HOST:PORT/DATABASE"Barcha katta harflarda yozilgan placeholder'larni database credential'laringiz bilan almashtiring.
Microsoft SQL Server / Azure SQL Server
Agar Microsoft SQL Server yoki Azure SQL Server ishlatayotgan bo'lsangiz, schema.prisma va .env fayllarini quyidagicha o'zgartiring:
schema.prisma
1datasource db {
2 provider = "sqlserver"
3}
4
5generator client {
6 provider = "prisma-client"
7 output = "../src/generated/prisma"
8 moduleFormat = "cjs"
9}.env
Barcha katta harflarda yozilgan placeholder'larni database credential'laringiz bilan almashtiring. Agar encrypt uchun nima yozishni bilmasangiz, ko'p hollarda standart qiymat true bo'ladi:
1DATABASE_URL="sqlserver://HOST:PORT;database=DATABASE;user=USER;password=PASSWORD;encrypt=true"Prisma Migrate bilan ikkita database jadvali yaratish
Ushbu bo'limda Prisma Migrate yordamida database'da ikkita yangi jadval yaratasiz. Prisma Migrate Prisma schema ichidagi deklarativ data model asosida SQL migration fayllarini generatsiya qiladi. Bu migration fayllari to'liq sozlanadi, shu sabab database'ning qo'shimcha xususiyatlarini yoki masalan seed qilish uchun qo'shimcha buyruqlarni ham qo'shishingiz mumkin.
schema.prisma fayliga quyidagi ikkita modelni qo'shing:
1model User {
2 id Int @default(autoincrement()) @id
3 email String @unique
4 name String?
5 posts Post[]
6}
7
8model Post {
9 id Int @default(autoincrement()) @id
10 title String
11 content String?
12 published Boolean? @default(false)
13 author User? @relation(fields: [authorId], references: [id])
14 authorId Int?
15}Prisma modellari tayyor bo'lgach, SQL migration fayllarini generatsiya qilib, ularni database'ga qo'llashingiz mumkin. Terminalda quyidagi buyruqni ishga tushiring:
1$ npx prisma migrate dev --name initBu prisma migrate dev buyrug'i SQL fayllarini generatsiya qiladi va ularni to'g'ridan-to'g'ri database'ga qo'llaydi. Bu holatda mavjud prisma katalogida quyidagi migration fayllari yaratiladi:
1$ tree prisma
2prisma
3├── dev.db
4├── migrations
5│ └── 20201207100915_init
6│ └── migration.sql
7└── schema.prismaExpand to view the generated SQL statements
SQLite database'ingizda quyidagi jadvallar yaratiladi:
1-- CreateTable
2CREATE TABLE "User" (
3 "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
4 "email" TEXT NOT NULL,
5 "name" TEXT
6);
7
8-- CreateTable
9CREATE TABLE "Post" (
10 "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
11 "title" TEXT NOT NULL,
12 "content" TEXT,
13 "published" BOOLEAN DEFAULT false,
14 "authorId" INTEGER,
15
16 FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE SET NULL ON UPDATE CASCADE
17);
18
19-- CreateIndex
20CREATE UNIQUE INDEX "User.email_unique" ON "User"("email");Prisma Client'ni o'rnatish va generatsiya qilish
Prisma Client - bu Prisma model ta'rifidan generatsiya qilinadigan type-safe database client. Shu yondashuv sabab Prisma Client aynan modellaringizga moslashtirilgan CRUD operatsiyalarini taqdim etadi.
Prisma Client'ni loyihaga o'rnatish uchun terminalda quyidagi buyruqni ishga tushiring:
1$ npm install @prisma/clientO'rnatilgach, loyiha uchun kerakli type'lar va Client'ni generatsiya qilish uchun generate buyrug'ini ishga tushiring. Schema'ga o'zgartirish kiritilsa, type'larni mos holda saqlash uchun generate buyrug'ini yana qayta ishga tushirishingiz kerak bo'ladi.
1$ npx prisma generatePrisma Client'dan tashqari, ishlatayotgan database turiga mos driver adapter ham kerak bo'ladi. SQLite uchun @prisma/adapter-better-sqlite3 driver'ini o'rnatishingiz mumkin.
1npm install @prisma/adapter-better-sqlite3Expand if you're using PostgreSQL, MySQL, MsSQL, or AzureSQL
- For PostgreSQL
1npm install @prisma/adapter-pg- For MySQL, MsSQL, AzureSQL:
1npm install @prisma/adapter-mariadbPrisma Client'ni NestJS service'larida ishlatish
Endi Prisma Client yordamida database query'larini yubora olasiz. Prisma Client bilan query yozish haqida ko'proq bilish uchun API documentation ni ko'ring.
NestJS ilovasini sozlayotganda, database query'lari uchun Prisma Client API'ni service ichida abstraksiya qilish ma'qul. Buning uchun PrismaClient instansiyasini yaratish va database'ga ulanishni boshqaradigan yangi PrismaService yarating.
src katalogi ichida prisma.service.ts nomli yangi fayl yarating va unga quyidagi kodni yozing:
1import { Injectable } from '@nestjs/common';
2import { PrismaClient } from './generated/prisma/client';
3import { PrismaBetterSqlite3 } from '@prisma/adapter-better-sqlite3';
4
5@Injectable()
6export class PrismaService extends PrismaClient {
7 constructor() {
8 const adapter = new PrismaBetterSqlite3({ url: process.env.DATABASE_URL });
9 super({ adapter });
10 }
11}Keyin Prisma schema'dagi User va Post modellari uchun database chaqiruvlarini bajaradigan service'larni yozishingiz mumkin.
Yana src katalogi ichida user.service.ts nomli yangi fayl yarating va unga quyidagi kodni yozing:
1import { Injectable } from '@nestjs/common';
2import { PrismaService } from './prisma.service';
3import { User, Prisma } from 'generated/prisma';
4
5@Injectable()
6export class UsersService {
7 constructor(private prisma: PrismaService) {}
8
9 async user(
10 userWhereUniqueInput: Prisma.UserWhereUniqueInput,
11 ): Promise<User | null> {
12 return this.prisma.user.findUnique({
13 where: userWhereUniqueInput,
14 });
15 }
16
17 async users(params: {
18 skip?: number;
19 take?: number;
20 cursor?: Prisma.UserWhereUniqueInput;
21 where?: Prisma.UserWhereInput;
22 orderBy?: Prisma.UserOrderByWithRelationInput;
23 }): Promise<User[]> {
24 const { skip, take, cursor, where, orderBy } = params;
25 return this.prisma.user.findMany({
26 skip,
27 take,
28 cursor,
29 where,
30 orderBy,
31 });
32 }
33
34 async createUser(data: Prisma.UserCreateInput): Promise<User> {
35 return this.prisma.user.create({
36 data,
37 });
38 }
39
40 async updateUser(params: {
41 where: Prisma.UserWhereUniqueInput;
42 data: Prisma.UserUpdateInput;
43 }): Promise<User> {
44 const { where, data } = params;
45 return this.prisma.user.update({
46 data,
47 where,
48 });
49 }
50
51 async deleteUser(where: Prisma.UserWhereUniqueInput): Promise<User> {
52 return this.prisma.user.delete({
53 where,
54 });
55 }
56}E'tibor bering, bu yerda service tashqariga chiqaradigan metodlar to'g'ri typed bo'lishi uchun Prisma Client generatsiya qilgan type'lardan foydalanilyapti. Shu bilan model type'larini qo'lda yozish va alohida interface yoki DTO fayllari yaratishdagi boilerplate kamayadi.
Endi xuddi shu ishni Post modeli uchun ham bajaring.
Yana src katalogi ichida post.service.ts nomli yangi fayl yarating va unga quyidagi kodni yozing:
1import { Injectable } from '@nestjs/common';
2import { PrismaService } from './prisma.service';
3import { Post, Prisma } from 'generated/prisma';
4
5@Injectable()
6export class PostsService {
7 constructor(private prisma: PrismaService) {}
8
9 async post(
10 postWhereUniqueInput: Prisma.PostWhereUniqueInput,
11 ): Promise<Post | null> {
12 return this.prisma.post.findUnique({
13 where: postWhereUniqueInput,
14 });
15 }
16
17 async posts(params: {
18 skip?: number;
19 take?: number;
20 cursor?: Prisma.PostWhereUniqueInput;
21 where?: Prisma.PostWhereInput;
22 orderBy?: Prisma.PostOrderByWithRelationInput;
23 }): Promise<Post[]> {
24 const { skip, take, cursor, where, orderBy } = params;
25 return this.prisma.post.findMany({
26 skip,
27 take,
28 cursor,
29 where,
30 orderBy,
31 });
32 }
33
34 async createPost(data: Prisma.PostCreateInput): Promise<Post> {
35 return this.prisma.post.create({
36 data,
37 });
38 }
39
40 async updatePost(params: {
41 where: Prisma.PostWhereUniqueInput;
42 data: Prisma.PostUpdateInput;
43 }): Promise<Post> {
44 const { data, where } = params;
45 return this.prisma.post.update({
46 data,
47 where,
48 });
49 }
50
51 async deletePost(where: Prisma.PostWhereUniqueInput): Promise<Post> {
52 return this.prisma.post.delete({
53 where,
54 });
55 }
56}Hozircha UsersService va PostsService Prisma Client'da mavjud CRUD query'larini o'rab turibdi. Real ilovada service qatlami business logic'ni ham shu yerga joylashtirish uchun ishlatiladi. Masalan, UsersService ichida foydalanuvchi parolini yangilaydigan updatePassword metodini yozishingiz mumkin.
Yangi service'larni app module ichida ro'yxatdan o'tkazishni unutmang.
REST API route'larini asosiy app controller'da implement qilish
Oxirida oldingi bo'limlarda yaratgan service'laringizdan foydalanib, ilovangizning turli route'larini implement qilasiz. Ushbu qo'llanma uchun barcha route'lar allaqachon mavjud AppController class'i ichiga joylashtiriladi.
app.controller.ts fayli tarkibini quyidagi kod bilan almashtiring:
1import {
2 Controller,
3 Get,
4 Param,
5 Post,
6 Body,
7 Put,
8 Delete,
9} from '@nestjs/common';
10import { UsersService } from './user.service';
11import { PostsService } from './post.service';
12import { User as UserModel, Post as PostModel } from 'generated/prisma';
13
14@Controller()
15export class AppController {
16 constructor(
17 private readonly userService: UsersService,
18 private readonly postService: PostsService,
19 ) {}
20
21 @Get('post/:id')
22 async getPostById(@Param('id') id: string): Promise<PostModel> {
23 return this.postService.post({ id: Number(id) });
24 }
25
26 @Get('feed')
27 async getPublishedPosts(): Promise<PostModel[]> {
28 return this.postService.posts({
29 where: { published: true },
30 });
31 }
32
33 @Get('filtered-posts/:searchString')
34 async getFilteredPosts(
35 @Param('searchString') searchString: string,
36 ): Promise<PostModel[]> {
37 return this.postService.posts({
38 where: {
39 OR: [
40 {
41 title: { contains: searchString },
42 },
43 {
44 content: { contains: searchString },
45 },
46 ],
47 },
48 });
49 }
50
51 @Post('post')
52 async createDraft(
53 @Body() postData: { title: string; content?: string; authorEmail: string },
54 ): Promise<PostModel> {
55 const { title, content, authorEmail } = postData;
56 return this.postService.createPost({
57 title,
58 content,
59 author: {
60 connect: { email: authorEmail },
61 },
62 });
63 }
64
65 @Post('user')
66 async signupUser(
67 @Body() userData: { name?: string; email: string },
68 ): Promise<UserModel> {
69 return this.userService.createUser(userData);
70 }
71
72 @Put('publish/:id')
73 async publishPost(@Param('id') id: string): Promise<PostModel> {
74 return this.postService.updatePost({
75 where: { id: Number(id) },
76 data: { published: true },
77 });
78 }
79
80 @Delete('post/:id')
81 async deletePost(@Param('id') id: string): Promise<PostModel> {
82 return this.postService.deletePost({ id: Number(id) });
83 }
84}Ushbu controller quyidagi route'larni implement qiladi:
GET
/post/:id:idorqali bitta post'ni olish/feed: Barcha published post'larni olish/filter-posts/:searchString:titleyokicontentbo'yicha post'larni filter qilish
POST
/post: Yangi post yaratish- Body:
title: String(required): post sarlavhasicontent: String(optional): post matniauthorEmail: String(required): post yaratgan foydalanuvchining email'i
- Body:
/user: Yangi foydalanuvchi yaratish- Body:
email: String(required): foydalanuvchi email manziliname: String(optional): foydalanuvchi ismi
- Body:
PUT
/publish/:id:idbo'yicha post'ni publish qilish
DELETE
/post/:id:idbo'yicha post'ni o'chirish
Xulosa
Ushbu recipe'da Prisma'ni NestJS bilan birga ishlatib REST API yaratishni o'rgandingiz. API route'larini implement qilgan controller PrismaService ga murojaat qiladi, u esa Prisma Client orqali database'ga query yuborib kiruvchi so'rovlarning ma'lumot ehtiyojini qoplaydi.
Agar NestJS bilan Prisma'dan foydalanish haqida ko'proq bilmoqchi bo'lsangiz, quyidagi resurslarni ko'ring:
- NestJS & Prisma
- Ready-to-run example projects for REST & GraphQL
- Production-ready starter kit
- Video: Accessing Databases using NestJS with Prisma (5min) by Marc Stammerjohann