آموزش TypeORM - معروف ترین او آر ام در تایپ‌اسکریپت

همونطور که از اسمش پیداست TypeORM یک او آر ام یا object-relational mapping برای تایپ اسکریپته یعنی یه سری از کلاس ها و توابع که کار با دیتابیس رو خیلی راحتتر و امن تر میکنن (توی گیت هاب بیشتر از 30 هزار ستاره داره). همونطور که میدونید typescript یکی از محبوب ترین زبان های برنامه نویسی دنیاست که از طریق اون و nodejs میشه کدنویسی سمت سرور یا بک اند انجام داد. توی این پست میخوایم راه اندازی یه بک اند با TypeORM و nodejs رو یاد بگیریم.

تایپ او آر ام - typeorm

نصب TypeORM

تایپ او آر ام از خیلی از دیتابیس های معروف مثل MySQL / MariaDB و PostgreSQL / CockroachDB و SQLite و Microsoft SQL Server و Oracle و … پشتیبانی میکنه. برای ایجاد یه پروژه با کد های اولیه می تونیم از این دستور استفاده کنیم:

npx typeorm init --name MyProject --database postgres

بجای MyProject اسم پروژه و فولدری که باید ایجاد بشه رو مینویسیم و بجای postgres هر دیتابیسی که میخوایم استفاده بشه. یکی از این مقادیر:

mysql, mariadb, postgres, cockroachdb, sqlite, mssql, sap, spanner, oracle, mongodb, cordova, react-native, expo, nativescript

اگه بخوایم typeorm رو به یه پروژه از قبل ایجاد شده اضافه کنیم هم با استفاده از دستور typeorm init میشه انجامش داد. قدم بعدی قرار دادن تنظیمات و اطلاعات دیتابیس در فایل data-source.ts هست که تایپ او ار ام بتونه به درستی به دیتابیس وصل بشه.

تعریف مدل در TypeORM

توی تایپ او ار ام هم می تونیم از روش Active Record و هم از روش Data Mapper استفاده کنیم. توی روش Active Record همه ی متد های مدل (مثل اینسرت و آپدیت) داخل کلاس خود مدل نوشته میشه. ولی توی روش Data Mapper این متد ها رو توی کلاس جدا مینویسین که اصطلاحا میگن “repository” و کلاس مدل فقط شامل دیتای مدل میشه. توی این آموزش از روش Active Record استفاده میکنیم.

نمونه کلاس یک مدل در تایپ او ار ام:

import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from "typeorm"

@Entity()
export class User extends BaseEntity {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    firstName: string

    @Column()
    lastName: string

    @Column()
    isActive: boolean
}

با استفاده از دکوراتور @Entity مشخص می کنیم که این کلاس یه مدل یا انتیتی هست و تایپ او ار ام یه جدول توی دیتابیس برای این مدل ایجاد میکنه. با دکوراتور @Column() هم مشخصات این مدل یا همون ستون های جدول رو تعیین میکنیم. این دکوراتور نوع و دیتا تایپ ستون ساده رو از روی نوع property مثل string و integer و boolean تشخیص میده ولی میتونیم خودمون هم مشخصات ستون رو تعیین کنیم @Column({ type: "int" }) همچنین یه سری دکوراتور برای تنظیمات ستون های پر استفاده هم هست مثل @PrimaryGeneratedColumn() که یه ستون primary با قابلیت auto increment اضافه میکنه.

عملیات CRUD یا ایجاد/خواندن/بروزرسانی/حذف

در روش Active Record کلاس مدل باید کلاس BaseEntity رو اکستند کنه تا بتونیم از این متد ها استفاده کنیم:

// مثال ذخیره روی دیتابیس
const user = new User()
user.firstName = "رضا"
user.lastName = "اکبری"
user.isActive = true
await user.save()

// مثال حذف از دیتابیس
await user.remove()

// مثال های دریافت از دیتابیس
const users = await User.find({ skip: 2, take: 5 })
const newUsers = await User.findBy({ isActive: true })
const reza = await User.findOneBy({ firstName: "رضا", lastName: "اکبری" })

همچنین میتونیم داخل کلاس مدل متد های دیگه ای تعریف و استفاده کنیم مثلا:

...

@Entity()
export class User extends BaseEntity {
    ...

    deactivate() {
        this.isActive = false;
        return this.save()
    }

    static findActive(firstName: string) {
        return this.createQueryBuilder("user")
            .where("user.firstName = :firstName", { firstName })
            .andWhere("user.isActive = true")
            .getMany()
    }
}

و استفاده به این صورت:

const users = User.findActive('رضا')
users.forEach(user => user.deactivate())

رابطه یا relation مدل ها

برای تعریف ریلیشن بین مدل ها یه سری دکوراتور دیگه وجود داره:

  • یک-به-یک با استفاده از @OneToOne

  • چند-به-یک با استفاده از @ManyToOne

  • یک-به-چند با استفاده از @OneToMany

  • چند-به-چند با استفاده از @ManyToMany

برای مثال به این دو مدل و ریلیشن تعریف شده بینشون توجه کنید:

import { Entity, BaseEntity, PrimaryGeneratedColumn, Column, ManyToMany } from "typeorm"
import { Question } from "./Question"

@Entity()
export class Category extends BaseEntity {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    name: string

    @ManyToMany((type) => Question, (question) => question.categories)
    questions: Question[]
}
import {
    Entity,
    BaseEntity,
    PrimaryGeneratedColumn,
    Column,
    ManyToMany,
    JoinTable,
} from "typeorm"
import { Category } from "./Category"

@Entity()
export class Question extends BaseEntity {
    @PrimaryGeneratedColumn()
    id: number

    @Column()
    title: string

    @Column()
    text: string

    @ManyToMany((type) => Category, (category) => category.questions)
    @JoinTable()
    categories: Category[]
}

برای اطلاعات بیشتر و آپشن های مختلف و نحوه کار با ریلیشن ها داکیومنت تایپ او ار ام رو مشاهده کنید.

رویداد ها و Listener های مدل

داخل مدل میتونیم توابع خاصی تعریف کنیم که موقع رخداد رویداد های خاص فراخوانی و اجرا بشن. مثلا فرض کنید میخوایم هر بار که یه پست ذخیره میشه لاگ ثبت کنیم. بجای اینکه کد های ثبت لاگ رو همه جا تکرار کنیم میتونیم داخل یه listener به رویداد “ذخیره”، کد ها رو قرار بدیم و بعد هر موقع که یه پست ذخیره میشه این تابع اجرا و لاگ انجام میشه. برای تعیین یه متد داخل کلاس مدل به عنوان listener از این دکوراتور ها میتونیم استفاده کنیم که اسم هاشون دقیقا مشخص میکنه مربوط به چه رویدادی هستند:

  • @AfterLoad

  • @BeforeInsert

  • @AfterInsert

  • @BeforeUpdate

  • @AfterUpdate

  • @BeforeRemove

  • @AfterRemove

  • @BeforeSoftRemove

  • @AfterSoftRemove

  • @BeforeRecover

  • @AfterRecover

مثال لاگ رو اگر بخوایم بنویسیم به این صورت میشه:

@Entity()
export class Post extends BaseEntity {

    @AfterInsert()
    @AfterUpdate()
    myLoggingFunction() {
        // این تابع موقع ذخیره (هم ایجاد و هم آپدیت) پست 
        // اجرا میشه و this همون پست ذخیره شده هست
    }

}

کدنویسی

تا اینجا با ستاپ اولیه TypeORM آشنا شدید. اگه میخواین یه مثال کامل و واقعی هم ببینید توی این ویدیو من یه سایت کامل رو با TypeORM و React درست کردم و مراحل صفر تا صد راه اندازیش رو توضیح دادم:

اگه سوالی هم داشتین در بخش پرسش و پاسخ رسانیکا مطرح کنید تا پاسخ داده بشه. در نهایت امیدوارم این مطلب برای شما مفید واقع شده باشه.

منتشر شده در رسانیکا، پلتفرم اشتراک‌گذاری محتوا
یک برنامه‌نویس
کامنت ها