Retseptlar3 min read

SQL (TypeORM)

##### Bu bo'lim faqat TypeScript uchun

Bu bo'lim faqat TypeScript uchun

Warning Bu maqolada custom provider mexanizmi yordamida TypeORM package'i asosida DatabaseModule ni noldan qanday yaratish ko'rsatiladi. Natijada bu yechimda qo'shimcha overhead ko'p bo'ladi. Buni tayyor @nestjs/typeorm package'idan foydalanib chetlab o'tish mumkin. Ko'proq ma'lumot uchun bu yerga qarang.

TypeORM node.js ekotizimidagi eng yetuk Object Relational Mapper (ORM) lardan biri hisoblanadi. U TypeScript'da yozilgani uchun Nest framework bilan juda yaxshi ishlaydi.

Boshlash

Bu kutubxona bilan ishlashni boshlash uchun barcha kerakli dependency'larni o'rnatishimiz kerak:

Terminal
1$ npm install --save typeorm mysql2

Birinchi qadam typeorm package'idan import qilingan new DataSource().initialize() orqali database bilan ulanishni o'rnatishdir. initialize() funksiyasi Promise qaytaradi, shu sabab async provider yaratishimiz kerak bo'ladi.

TypeScript
database.providers
1import { DataSource } from 'typeorm';
2
3export const databaseProviders = [
4  {
5    provide: 'DATA_SOURCE',
6    useFactory: async () => {
7      const dataSource = new DataSource({
8        type: 'mysql',
9        host: 'localhost',
10        port: 3306,
11        username: 'root',
12        password: 'root',
13        database: 'test',
14        entities: [
15            __dirname + '/../**/*.entity{.ts,.js}',
16        ],
17        synchronize: true,
18      });
19
20      return dataSource.initialize();
21    },
22  },
23];
Warning

synchronize: true ni production'da ishlatmaslik kerak, aks holda production ma'lumotlarini yo'qotib qo'yishingiz mumkin.

Hint

Best practice'ga amal qilib, custom provider'ni *.providers.ts suffix'iga ega alohida faylda e'lon qildik.

Keyin bu provider'larni ilovaning qolgan qismi uchun accessible qilish maqsadida export qilamiz.

TypeScript
database.module
1import { Module } from '@nestjs/common';
2import { databaseProviders } from './database.providers';
3
4@Module({
5  providers: [...databaseProviders],
6  exports: [...databaseProviders],
7})
8export class DatabaseModule {}

Endi DATA_SOURCE obyektini @Inject() dekoratori orqali inject qila olamiz. DATA_SOURCE async provider'iga bog'liq har bir class Promise resolve bo'lguncha kutadi.

Repository pattern'i

TypeORM repository design pattern'ni qo'llab-quvvatlaydi, shu sabab har bir entity o'z Repository'siga ega bo'ladi. Bu repository'larni database connection orqali olish mumkin.

Ammo avval kamida bitta entity kerak. Biz rasmiy hujjatlardagi Photo entity'dan qayta foydalanamiz.

TypeScript
photo.entity
1import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
2
3@Entity()
4export class Photo {
5  @PrimaryGeneratedColumn()
6  id: number;
7
8  @Column({ length: 500 })
9  name: string;
10
11  @Column('text')
12  description: string;
13
14  @Column()
15  filename: string;
16
17  @Column('int')
18  views: number;
19
20  @Column()
21  isPublished: boolean;
22}

Photo entity photo direktoriyasiga tegishli. Bu direktoriyaning o'zi PhotoModule ni ifodalaydi. Endi Repository provider yarataylik:

TypeScript
photo.providers
1import { DataSource } from 'typeorm';
2import { Photo } from './photo.entity';
3
4export const photoProviders = [
5  {
6    provide: 'PHOTO_REPOSITORY',
7    useFactory: (dataSource: DataSource) => dataSource.getRepository(Photo),
8    inject: ['DATA_SOURCE'],
9  },
10];
Warning

Real loyihalarda magic string'lardan qochish kerak. PHOTO_REPOSITORY ham, DATA_SOURCE ham alohida constants.ts faylida saqlangani ma'qul.

Endi Repository<Photo> ni @Inject() dekoratori orqali PhotoService ichiga inject qila olamiz:

TypeScript
photo.service
1import { Injectable, Inject } from '@nestjs/common';
2import { Repository } from 'typeorm';
3import { Photo } from './photo.entity';
4
5@Injectable()
6export class PhotoService {
7  constructor(
8    @Inject('PHOTO_REPOSITORY')
9    private photoRepository: Repository<Photo>,
10  ) {}
11
12  async findAll(): Promise<Photo[]> {
13    return this.photoRepository.find();
14  }
15}

Database connection asynchronous, lekin Nest bu jarayonni oxirgi foydalanuvchi uchun deyarli sezilmas qiladi. PhotoRepository db connection tayyor bo'lguncha kutadi, PhotoService esa repository ishlatishga tayyor bo'lguncha kechiktiriladi. Barcha class'lar instantiate qilingach, butun ilova ishga tushishi mumkin.

Yakuniy PhotoModule quyidagicha bo'ladi:

TypeScript
photo.module
1import { Module } from '@nestjs/common';
2import { DatabaseModule } from '../database/database.module';
3import { photoProviders } from './photo.providers';
4import { PhotoService } from './photo.service';
5
6@Module({
7  imports: [DatabaseModule],
8  providers: [
9    ...photoProviders,
10    PhotoService,
11  ],
12})
13export class PhotoModule {}
Hint

PhotoModule ni root AppModule ichiga import qilishni unutmang.