نحوه راه اندازی TypeORM DataSource در پروژه NestJS
سلام! 👋 از زمانی که کار با NestJS را شروع کردم، به دنبال راهی مطمئن برای مدیریت پایگاه داده خود با TypeORM بودم. امروز، من سفرم و مراحلی را که برای تنظیم آن انجام دادم به اشتراک میگذارم.
خوب، قبل از اینکه وارد آن شویم، بیایید سعی کنیم بفهمیم TypeORM و NestJS چیست.
فهرست مطالب:
چگونه یک پروژه NestJS را راه اندازی کنیم
نحوه تنظیم TypeORM DataSource برای پایداری داده
گسترش مخزن منبع داده برای روش های سفارشی
TypeORM چیست؟
TypeORM یک ابزار Object-Relational Mapping (ORM) است که کار با پایگاه های داده را در برنامه های Node.js و TypeScript ساده می کند. این پایگاه داده های مختلفی مانند MySQL، PostgreSQL، SQLite و غیره را پشتیبانی می کند و به توسعه دهندگان این امکان را می دهد تا از مفاهیم برنامه نویسی شی گرا به جای پرداختن به پرس و جوهای سطح پایین SQL استفاده کنند.
TypeORM همچنین ویژگی هایی مانند مهاجرت طرحواره، ساخت پرس و جو و مدیریت روابط بین جداول را فراهم می کند.
NestJS چیست؟
NestJS یک فریم ورک پیشرو Node.js است که برای ساخت برنامه های کاربردی سمت سرور کارآمد، قابل اعتماد و مقیاس پذیر طراحی شده است. از ویژگی های TypeScript استفاده می کند تا توسعه دهندگان را قادر به نوشتن کدهای ساختاریافته و قابل نگهداری کند.
NestJS از یک الگوی معماری مدولار استفاده می کند و به شما امکان می دهد کد خود را در ماژول ها، کنترلرها، سرویس ها و ارائه دهندگان سازماندهی کنید. پشتیبانی داخلی از آپشن های ی مانند تزریق وابستگی، میانافزار و GraphQL را فراهم میکند و آن را به گزینهای محبوب برای ساخت برنامههای وب مدرن و API تبدیل میکند.
علاوه بر این، NestJS به طور یکپارچه با سایر کتابخانه ها و چارچوب ها، از جمله TypeORM، ادغام می شود تا گردش کار توسعه را ساده کند. در زیر هود، از یک چارچوب سرور HTTP قوی مانند Express (پیشفرض) استفاده میکند و میتواند برای استفاده از سایر چارچوبهای سرور HTTP Node.js پیکربندی شود.
خوب، این خیلی است، درست است؟ خوب، قبل از اینکه ادامه دهیم، بیایید سعی کنیم عبارت "NestJS یک چارچوب Node.js مترقی است" را تجزیه کنیم، که به سادگی به این معنی است که NestJS از آخرین ویژگی های زبان جاوا اسکریپت و فریمورک های سرور استفاده می کند و در نتیجه انعطاف پذیری را برای توسعه دهندگان برای نوشتن فراهم می کند. کد در مناسب ترین زبان برای پروژه های خود. (منبع)
پیش نیازهای آموزشی
Node.js. حداقل نسخه 18
npm حداقل نسخه 8
Postgresql. از اینجا دانلود کنید
آشنایی اولیه با Typescirpt و Nestjs
Pgadmin 4. از اینجا دانلود کنید
چگونه یک پروژه NestJS را راه اندازی کنیم
دستورات زیر را برای نصب پروژه NestJS خود اجرا کنید:
npm i -g @nestjs/cli # install nestj cli globally nest new simple-crm # start a new nestjs project
پس از نصب، سرور توسعه را اجرا کنید:
npm run start:dev # start the app in watch mode
اکنون، بیایید پروژه خود را آزمایش کنیم تا ببینیم آیا nest-cli
به درستی همه کد صفحه دیگ بخار را با ارسال یک درخواست دریافت به آدرس ریشه / تنظیم کرده است.
خوب! پروژه ما در حال اجر است.
نحوه تنظیم TypeORM DataSource برای پایداری داده
npm install --save @nestjs/typeorm typeorm # nestjs typeorm drivers npm install --save pg # typeorm postgressql driver
بیایید پایگاه داده پروژه را از رابط Pgadmin 4 ایجاد کنیم
رابط Pgadmin 4 را باز کنید و روی تب Databases کلیک راست کنید تا پایگاه داده جدید ایجاد کنید.
تایید کنید پایگاه داده شما با موفقیت ایجاد شده است.
عالی است، وقت آن است که پایگاه داده را با استفاده از TypeORM به برنامه NestJS خود اضافه کنیم.
پوشه جدید، منبع داده را در پوشه src/ برنامه خود ایجاد کنید، مانند این 👇
یک فایل typeorm.module.ts جدید در پوشه datasource ایجاد کنید و کد زیر را اضافه کنید:
import { DataSource } from 'typeorm'; import { Global, Module } from '@nestjs/common'; @Global() // makes the module available globally for other modules once imported in the app modules @Module({ imports: [], providers: [ { provide: DataSource, // add the datasource as a provider inject: [], useFactory: async () => { // using the factory function to create the datasource instance try { const dataSource = new DataSource({ type: 'postgres', host: 'localhost', port: 5432, username: 'ayo', password: 'haywon', database: 'simple-crm_db', synchronize: true, entities: [`${__dirname}/../**/**.entity{.ts,.js}`], // this will automatically load all entity file in the src folder }); await dataSource.initialize(); // initialize the data source console.log('Database connected successfully'); return dataSource; } catch (error) { console.log('Error connecting to database'); throw error; } }, }, ], exports: [DataSource], }) export class TypeOrmModule {}
ماژول TypeORM را به آرایه واردات ماژول App اضافه کنید، مانند این 👇
import { Module } from '@nestjs/common'; import { AppController } from './app.controller'; import { AppService } from './app.service'; import { TypeOrmModule } from './datasource/typeorm.module'; @Module({ imports: [TypeOrmModule], controllers: [AppController], providers: [AppService], }) export class AppModule {}
سپس ذخیره کرده و از کنسول خود تأیید کنید که آیا پایگاه داده با موفقیت وصل شده است.
اگر دیدید که پایگاه داده با موفقیت متصل شده است، کار خوبی است! در غیر این صورت، به مراحل قبلی برگردید تا ببینید آیا تنظیمات را به درستی دنبال کرده اید یا خیر.
اکنون، میتوانیم با استفاده از TypeORM به مصرف سرویس datasource
خود ادامه دهیم.
بیایید ماژول users
، کنترلکننده، ارائهدهنده و موجودیت ایجاد کنیم تا با پایگاه داده جدید متصل شده خود تعامل داشته باشیم.
nest g module users && nest g service users && nest g controller users
دستور بالا ماژول users
، سرویس و کنترلر را تولید می کند و app.module.ts را با ماژول users
به روز می کند.
کد زیر را داخل فایل users.entity.ts اضافه کنید و سرور توسعه خود را مجددا راه اندازی کنید تا جدول user
در پایگاه داده ایجاد شود.
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm'; @Entity('user') export class UserEntity { @PrimaryGeneratedColumn() id: number; @Column({ unique: true }) username: string; @Column() password: string; }
رابط Pgadmin 4 خود را تحلیل کنید و تأیید کنید که TypeORM به طور خودکار UserEntity
را بارگیری کرده و جدول user
را در پایگاه داده شما ایجاد کرده است، مانند این 👇.
اگر ابتدا پایگاه داده را نمی بینید، ممکن است بخواهید آن را به روز کنید.
اکنون بیایید اولین کنترل کننده خدمات users
خود را پیاده سازی کنیم، کد زیر را به فایل users.service.ts خود اضافه کنیم:
import { HttpException, HttpStatus, Injectable, InternalServerErrorException, Logger, } from '@nestjs/common'; import { DataSource } from 'typeorm'; import { UserEntity } from './users.entity'; export interface CreateUser { username: string; password: string; } @Injectable() export class UsersService { private userRepository; private logger = new Logger(); // inject the Datasource provider constructor(private dataSource: DataSource) { // get users table repository to interact with the database this.userRepository = this.dataSource.getRepository(UserEntity); } // create handler to create new user and save to the database async createUser(createUser: CreateUser): Promise<UserEntity> { try { const user = await this.userRepository.create(createUser); return await this.userRepository.save(user); } catch (err) { if (err.code == 23505) { this.logger.error(err.message, err.stack); throw new HttpException('Username already exists', HttpStatus.CONFLICT); } this.logger.error(err.message, err.stack); throw new InternalServerErrorException( 'Something went wrong, Try again!', ); } } }
ما متد createUser
اضافه کردهایم تا زمانی که یک درخواست POST با بدنه درخواست مورد نیاز به کنترلکننده نقطه پایانی ارسال میشود که از متد سرویس createUser
استفاده میکند، ایجاد یک کاربر را مدیریت کند.
تابع یک شی createUser
به عنوان آرگومان از نوع CreateUser
interface می گیرد. معمولاً، این باید یک DTO (Data Transfer Object) برای ساختار نوع داده و اعتبارسنجی باشد، اما از آنجایی که خارج از محدوده این آموزش است، ما از رابط فقط برای شکل داده استفاده می کنیم.
ما متد create
userRepository
را فراخوانی کردیم و سپس بازگشت آن را به متغیر user
برای نگه داشتن شی کاربر جدید ایجاد شده اختصاص دادیم. سپس متد save
را برای ذخیره شی در پایگاه داده فراخوانی کردیم.
اکنون، اجازه دهید از کنترلر سرویس createUser
در کنترلر users
خود استفاده کنیم که درخواست POST را برای ایجاد کاربر جدید مدیریت می کند.
import { Body, Controller, Post } from '@nestjs/common'; import { CreateUser, UsersService } from './users.service'; @Controller('users') export class UsersController { constructor(private userService: UsersService) {} @Post('/create') // handles the post request to /users/create endpoint to create new user async signUp(@Body() user: CreateUser) { return await this.userService.createUser(user); } }
نقطه پایانی جدید ایجاد شده را با ارسال یک درخواست POST به http://localhost:3000/users/create
با نام کاربری و رمز عبور به عنوان بدنه درخواست آزمایش کنید.
خوب، بیایید پایگاه داده را تحلیل کنیم تا مطمئن شویم که همه اینها است، زیرا ما قبلاً یک کد وضعیت پاسخ 201 دریافت کرده ایم که باید برای دانستن اینکه برنامه ما به راحتی با پایگاه داده ما با استفاده از منبع داده TypeORM در تعامل است کافی است.
گسترش مخزن منبع داده برای روش های سفارشی
خواه به دنبال بهینه سازی پرس و جوهای پایگاه داده، معرفی عملیات دستکاری داده های جدید، یا ادغام با خدمات شخص ثالث هستید، گسترش مخزن DataSource با روش های سفارشی می تواند یک تغییر بازی در تعامل یکپارچه با پایگاه داده باشد.
در اینجا، مزایای روشهای سفارشی را تحلیل میکنیم و راهنمای گام به گام پیادهسازی آنها در برنامههای NestJS شما را ارائه میکنیم. پس ، بیایید غواصی کنیم و پتانسیل کامل مخزن DataSource را باز کنیم!
برخی از مزایای اساسی روش های سفارشی مخزن عبارتند از:
عملکرد متناسب: روشهای سفارشی به توسعهدهندگان اجازه میدهد تا قابلیتهای خاصی را معرفی کنند که در مخزن استاندارد DataSource موجود نیستند. با تنظیم مخزن DataSource با روشهای سفارشی، توسعهدهندگان میتوانند موارد استفاده منحصربهفرد، عملیات دستکاری دادهها و تجمیعها یا بهینهسازیهایی را که برای نیازمندیهای پروژهشان ضروری است، تحلیل کنند.
عملکرد بهینه شده: روش های سفارشی را می توان برای بهینه سازی پرس و جوهای پایگاه داده، بازیابی داده ها و عملیات دستکاری داده ها طراحی کرد که منجر به بهبود عملکرد و کارایی می شود. با استفاده از روشهای سفارشی، توسعهدهندگان میتوانند الگوریتمهای بهینه، مکانیسمهای کش یا بهینهسازیهای پرس و جو را متناسب با نیازها و آپشن های برنامههای کاربردی خود پیادهسازی کنند.
قابلیت استفاده مجدد و نگهداری کد بهبود یافته: روش های سفارشی قابلیت استفاده مجدد کد را با کپسوله کردن منطق، الگوریتم ها یا عملیات خاص در اجزای قابل استفاده مجدد افزایش می دهند. با مدولار کردن روشهای سفارشی، توسعهدهندگان میتوانند پایگاههای کد تمیزتر، سازمانیافتهتر و قابل نگهداریتر را حفظ کنند و مدیریت، اشکالزدایی و ارتقای مخزن DataSource را در دراز مدت آسانتر کنند.
خوب، همین است، بیایید به سمت عمل حرکت کنیم. پس ، ما یک برنامه CRM ساده داریم که با مدیریت کاربر ارتباط دارد. بیایید یک روش مخزن سفارشی اضافه کنیم که می تواند به ما کمک کند کاربران را بر اساس نام کاربری فیلتر کنیم.
برای پیاده سازی این، اجازه دهید ماژول datasource
و سرویس datasource
خود را ایجاد کنیم. ما قصد داریم این فایل ها را ایجاد کنیم تا با اصول ماژولار بودن الگوی معماری NestJS هماهنگ شوند.
فایل ها را در پوشه منبع داده ای که قبلا ایجاد کرده اید ایجاد کنید و کد زیر را اضافه کنید:
// datasource.module.ts import { Module } from '@nestjs/common'; import { TypeOrmModule } from './typeorm.module'; import { DataSourceService } from './datasource.service'; @Module({ imports: [TypeOrmModule], providers: [DataSourceService], exports: [DataSourceService], }) export class DataSourceModule {}
// datasource.service.ts import { Injectable } from '@nestjs/common'; import { UserEntity } from 'src/users/users.entity'; import { DataSource } from 'typeorm'; export interface UsernameQuery { username: string; } @Injectable() export class DataSourceService { constructor(private dataSource: DataSource) {} // extend userRepository to add custom methods userCustomRepository = this.dataSource.getRepository(UserEntity).extend({ async filterUser(usernameQuery: UsernameQuery): Promise<UserEntity[]> { const { username } = usernameQuery; console.log(username); // initialize a query builder for the userrepository const query = this.createQueryBuilder('user'); // filter user where username is like the passed username query.where('(LOWER(user.username) LIKE LOWER(:username))', { username: `%${username}%`, }); return await query.getMany(); }, }); }
از کد بالا datasource.service.ts ، UserRepository
را با فراخوانی متد getRepository
در سرویس dataSource
و ارسال UserEntity
به عنوان آرگومان برای دریافت مخزن برای جدول خاص، گسترش دادیم.
سپس متد extend
را در userRepository
که از getRepository
خود برگشتیم فراخوانی کردیم تا متد سفارشی خود را اضافه کنیم. در متد extend
خود، یک شی ارسال کردیم که حاوی تمام متدهای سفارشی ما برای مخزن سفارشی است که به userCustomRepository
اختصاص دادهایم. در اینجا، ما فقط یک روش سفارشی را به مخزن کاربر سفارشی خود اضافه کرده ایم که filterUser
است. این یک پرس و جو فیلتر را بر روی جدول کاربر توسط نام کاربری ارائه شده اجرا می کند.
از آنجایی که DataSourseService
ما تزریقی است، میتوانیم آن را در UserService
خود تزریق کنیم و پس از اضافه کردن DataSourceModule
به آرایه واردات ماژول کاربر، آن را به روش جدید filterUser
مصرف کنیم.
// users.module.ts import { Module } from '@nestjs/common'; import { UsersController } from './users.controller'; import { UsersService } from './users.service'; import { DataSourceModule } from 'src/datasource/datasource.module'; @Module({ imports: [DataSourceModule], // add the DataSourceModule to the import array providers: [UsersService], controllers: [UsersController], }) export class UsersModule {}
بیایید روش فیلتر را از CustomUserRepository
در UserService
خود مصرف کنیم تا کاربران را با هر نام کاربری که هنگام ارسال درخواست به عنوان آرگومان درخواست ما ارسال می شود فیلتر کنیم.
// users.service.ts import { HttpException, HttpStatus, Injectable, InternalServerErrorException, Logger, } from '@nestjs/common'; import { DataSource } from 'typeorm'; import { UserEntity } from './users.entity'; import { DataSourceService, UsernameQuery, } from 'src/datasource/datasource.service'; export interface CreateUser { username: string; password: string; } @Injectable() export class UsersService { private userRepository; private customUserRepository; private logger = new Logger(); // inject the Datasource provider constructor( private dataSource: DataSource, private dataSourceService: DataSourceService, // inject our datasource service ) { // get users table repository to interact with the database this.userRepository = this.dataSource.getRepository(UserEntity); // assigning the dataSourceService userCustomRepository to the class customUserRepository this.customUserRepository = this.dataSourceService.userCustomRepository; } // create handler to create new user and save to the database async createUser(createUser: CreateUser): Promise<UserEntity> { try { const user = await this.userRepository.create(createUser); return await this.userRepository.save(user); } catch (err) { if (err.code == 23505) { this.logger.error(err.message, err.stack); throw new HttpException('Username already exists', HttpStatus.CONFLICT); } this.logger.error(err.message, err.stack); throw new InternalServerErrorException( 'Something went wrong, Try again!', ); } } // the userService filterByUsername handler async filterByUsername(usernameQuery: UsernameQuery): Promise<UserEntity[]> { try { // calling the customUserRepository filterUser custom method return await this.customUserRepository.filterUser(usernameQuery); } catch (err) { this.logger.error(err.message, err.stack); throw new InternalServerErrorException( 'Something went wrong, Try again!', ); } } }
از موارد بالا، کدی را که ما DataSourceService
سفارشی خود را با گفت ن موارد زیر به private dataSourceService: DataSourceService,
.
سرویس filterByUsername
درخواستی را که ما در روش سفارشی filterUser
مصرف میکنیم رسیدگی میکند await this .customUserRepository.filterUser(usernameQuery);
، که یک وعده را برمی گرداند.
اکنون، بیایید از این کنترلر سرویس در کنترلر کاربر خود برای فیلتر کردن کاربران بر اساس نام کاربری خود استفاده کنیم.
// users.controller.ts import { Body, Controller, Get, Post, Query } from '@nestjs/common'; import { CreateUser, UsersService } from './users.service'; import { UserEntity } from './users.entity'; import { UsernameQuery } from 'src/datasource/datasource.service'; @Controller('users') export class UsersController { constructor(private userService: UsersService) {} @Post('/create') // handles the post request to /users/create endpoint to create new user async signUp(@Body() user: CreateUser): Promise<UserEntity> { return await this.userService.createUser(user); } @Get('') // get request handler that returns the filtered results of the users table async filterUser( @Query() usernameQuery: UsernameQuery // extracts the username query param for the endpoint url, ): Promise<UserEntity[]> { return await this.userService.filterByUsername(usernameQuery); } }
نقطه پایانی فیلتر ما را آزمایش کنید،
در اینجا، ما یک فهرست با یک شی کاربر با نام کاربری مانند نام کاربری که به عنوان پرس و جو ارسال کردیم، دریافت کردیم.
نتیجه
وویلا! تمام است، اکنون شما آماده شروع کار با NestJS، TypeORM و DataSource هستید.
با تشکر برای خواندن!
اگر آن را مفید یافتید، لطفاً آن را با دوستان و همکاران خود به اشتراک بگذارید! منتظر مطالب روشنگرتر باشید و بیایید با هم به یادگیری و رشد ادامه دهیم. به سلامتی برای ساخت راه حل های هوشمندتر و کارآمدتر با NestJS!
منابع
دوره کامل NestJS را یاد بگیرید
ارسال نظر