۲۹ شهریور ۱۴۰۳

Techboy

اخبار و اطلاعات روز تکنولوژی

Prisma.js: کد اول ORM در جاوا اسکریپت

یک تور عملی از ابزار پیشرو نگاشت شی رابطه‌ای جاوا اسکریپت، که می‌توانید با MongoDB و پایگاه‌های داده سنتی استفاده کنید، دریافت کنید.

یک تور عملی از ابزار پیشرو نگاشت شی رابطه‌ای جاوا اسکریپت، که می‌توانید با MongoDB و پایگاه‌های داده سنتی استفاده کنید، دریافت کنید.

Prisma یک لایه نگاشت داده محبوب (ORM) برای جاوا اسکریپت و TypeScript سمت سرور است. هدف اصلی آن ساده سازی و خودکارسازی نحوه حرکت داده ها بین ذخیره سازی و کد برنامه است. Prisma از طیف وسیعی از ذخیره‌گاه‌های داده پشتیبانی می‌کند و یک لایه انتزاعی قدرتمند و در عین حال انعطاف‌پذیر برای ماندگاری داده‌ها فراهم می‌کند. با این تور اولین کد، احساس Prisma و برخی از ویژگی های اصلی آن را پیدا کنید.

یک لایه ORM برای جاوا اسکریپت

نقشه‌نگاری رابطه‌ای شی (ORM) توسط چارچوب Hibernate در جاوا پیشگام شد. هدف اولیه نگاشت شی-رابطه ای غلبه بر به اصطلاح عدم تطابق امپدانس بین کلاس های جاوا و جداول RDBMS بود. از این ایده، مفهوم بلندپروازانه تر از یک لایه پایداری همه منظوره برای برنامه ها رشد کرد. Prisma یک تکامل مدرن مبتنی بر جاوا اسکریپت از لایه ORM جاوا است.

Prisma از محدوده ای از پایگاه های داده SQL پشتیبانی می کند و گسترش یافته است برای گنجاندن داده‌های NoSQL، MongoDB. صرف نظر از نوع ذخیره‌گاه داده، هدف اصلی باقی می‌ماند: دادن یک چارچوب استاندارد به برنامه‌ها برای مدیریت ماندگاری داده‌ها.

مدل دامنه

ما از یک مدل دامنه ساده برای بررسی انواع روابط در یک مدل داده استفاده خواهیم کرد: چند به یک، یک به چند، و چند به چند. (از یک به یک می گذریم، که بسیار شبیه به یک به یک است.) 

Prisma از یک تعریف مدل (یک طرحواره) استفاده می کند که به عنوان لولا بین برنامه کاربردی و ذخیره داده عمل می کند. یکی از روش‌های ساخت اپلیکیشن، که در اینجا به آن می‌پردازیم، این است که با این تعریف شروع کنیم و سپس کد را از آن بسازیم. Prisma به طور خودکار طرحواره را در دیتا استور اعمال می کند.

درک قالب تعریف مدل Prisma سخت نیست و می توانید از یک ابزار گرافیکی، PrismaBuilder استفاده کنید، برای ساختن یکی مدل ما از یک برنامه کاربردی توسعه ایده مشترک پشتیبانی می کند، بنابراین مدل های کاربر، ایده و برچسب را خواهیم داشت. یک کاربر می‌تواند بسیاری از ایده‌ها (یک به چند) و یک Idea دارای یک کاربر، مالک باشد. (چند به یک). ایده‌ها و برچسب‌ها یک رابطه چند به چند را تشکیل می‌دهند. لیست ۱ تعریف مدل را نشان می دهد.


datasource db {
  provider = "sqlite"
  url      = "file:./dev.db"
}

generator client {
  provider = "prisma-client-js"
}

model User {
  id       Int      @id @default(autoincrement())
  name     String
  email    String   @unique
  ideas    Idea[]
}

model Idea {
  id          Int      @id @default(autoincrement())
  name        String
  description String
  owner       User     @relation(fields: [ownerId], references: [id])
  ownerId     Int
  tags        Tag[]
}

model Tag {
  id     Int    @id @default(autoincrement())
  name   String @unique
  ideas  Idea[]
}

فهرست ۱ شامل یک تعریف منبع داده (یک پایگاه داده ساده SQLite که Prisma برای اهداف توسعه شامل می‌شود) و یک تعریف مشتری با “مشتری ژنراتور” تنظیم شده روی prisma-client-js است. دومی به این معنی است که Prisma یک کلاینت جاوا اسکریپت تولید می کند که برنامه می تواند از آن برای تعامل با نقشه ایجاد شده توسط تعریف استفاده کند.

Llama Chat و Code Llama در کدنویسی خوب هستند

در مورد تعریف مدل، توجه داشته باشید که هر مدل دارای یک فیلد id است و ما از حاشیه نویسی Prisma @default(autoincrement()) برای دریافت خودکار استفاده می کنیم. شناسه عدد صحیح افزایش یافته است.

برای ایجاد رابطه از User به Idea، به نوع Idea با براکت‌های آرایه ارجاع می‌دهیم: Idea[]. این می گوید: مجموعه ای از ایده ها را برای کاربر به من بدهید. در طرف دیگر رابطه، شما به Idea یک کاربر می دهید با: owner User @relation(فیلدها: [ownerId]، مراجع: [id]) .

علاوه بر روابط و فیلدهای شناسه کلیدی، تعاریف فیلدها ساده هستند. رشته برای رشته و غیره.

پروژه را ایجاد کنید

ما از یک پروژه ساده برای کار با قابلیت‌های Prisma استفاده می‌کنیم. اولین قدم ایجاد یک پروژه Node.js جدید و افزودن وابستگی به آن است. پس از آن، می‌توانیم تعریف فهرست ۱ را اضافه کنیم و از آن برای مدیریت پایداری داده‌ها با پایگاه داده SQLite داخلی Prisma استفاده کنیم.

برای شروع برنامه‌مان، یک دایرکتوری جدید ایجاد می‌کنیم، پروژه npm را راه‌اندازی می‌کنیم و وابستگی‌ها را همانطور که در فهرست ۲ نشان داده شده است، نصب می‌کنیم.


mkdir iw-prisma
cd iw-prisma
npm init -y
npm install express @prisma/client body-parser

mkdir prisma
touch prisma/schema.prisma

اکنون، یک فایل در prisma/schema.prisma ایجاد کنید و تعریف را از فهرست ۱ اضافه کنید. سپس، به Prisma بگویید که SQLite را با طرحی آماده کند، همانطور که در فهرست ۳ نشان داده شده است.

>


npx prisma migrate dev --name init
npx prisma migrate deploy

لیست ۳ به Prisma می‌گوید که پایگاه داده را "مهاجرت" کند، که به معنای اعمال تغییرات طرحواره از تعریف Prisma به خود پایگاه داده است. پرچم dev به Prisma می‌گوید که از نمایه توسعه استفاده کند، در حالی که --name یک نام دلخواه برای تغییر می‌دهد. پرچم deploy به prisma می‌گوید که تغییرات را اعمال کند.

از داده ها استفاده کنید

حالا اجازه ایجاد کاربران با نقطه پایانی RESTful در Express.js را می دهیم. می‌توانید کد سرور ما را در فهرست ۴ ببینید، که در داخل فایل iniw-prisma/server.js قرار می‌گیرد. لیست ۴ کد وانیلی اکسپرس است، اما به لطف Prisma می‌توانیم با کمترین تلاش در برابر پایگاه داده کارهای زیادی انجام دهیم.


const express = require('express');
const bodyParser = require('body-parser');
const { PrismaClient } = require('@prisma/client');

const prisma = new PrismaClient();
const app = express();
app.use(bodyParser.json());

const port = 3000;
app.listen(port, () => {
  console.log(`Server is listening on port ${port}`);
});

// Fetch all users
app.get('/users', async (req, res) => {
  const users = await prisma.user.findMany();
  res.json(users);
});

// Create a new user
app.post('/users', async (req, res) => {
  const { name, email } = req.body;
  const newUser = await prisma.user.create({ data: { name, email } });
  res.status(201).json(newUser);
});

در حال حاضر، فقط دو نقطه پایانی وجود دارد، /users GET برای دریافت لیستی از همه کاربران، و /user POST برای افزودن آنها. با فراخوانی prisma.user.findMany() و prisma.user.create()، می توانید ببینید که چقدر راحت می توانیم از سرویس گیرنده Prisma برای رسیدگی به این موارد استفاده استفاده کنیم. .

روش findMany() بدون هیچ آرگومان، تمام ردیف‌های پایگاه داده را برمی‌گرداند. متد create() یک شی با یک فیلد داده را می پذیرد که مقادیر ردیف جدید را در خود نگه می دارد (در این مورد، نام و ایمیل - به یاد داشته باشید که Prisma به طور خودکار یک شناسه منحصر به فرد برای ما ایجاد می کند).

اکنون می‌توانیم سرور را با: node server.js اجرا کنیم.

آزمایش با CURL

بیایید همانطور که در فهرست ۵ نشان داده شده است، نقاط پایانی خود را با CURL آزمایش کنیم.


$ curl http://localhost:3000/users
[]

$ curl -X POST -H "Content-Type: application/json" -d '{"name":"George Harrison","email":"george.harrison@example.com"}' http://localhost:3000/users
{"id":2,"name":"John Doe","email":"john.doe@example.com"}{"id":3,"name":"John Lennon","email":"john.lennon@example.com"}{"id":4,"name":"George Harrison","email":"george.harrison@example.com"}

$ curl http://localhost:3000/users
[{"id":2,"name":"John Doe","email":"john.doe@example.com"},{"id":3,"name":"John Lennon","email":"john.lennon@example.com"},{"id":4,"name":"George Harrison","email":"george.harrison@example.com"}]

فهرست ۵ به ما نشان می‌دهد که همه کاربران را دریافت می‌کنیم و یک مجموعه خالی پیدا می‌کنیم، سپس کاربران را اضافه می‌کنیم، سپس مجموعه پر شده را دریافت می‌کنیم.

بعد، یک نقطه پایانی اضافه می‌کنیم که به ما امکان می‌دهد ایده‌هایی ایجاد کنیم و از آنها در رابطه با کاربران استفاده کنیم، مانند فهرست ۶.


app.post('/users/:userId/ideas', async (req, res) => {
  const { userId } = req.params;
  const { name, description } = req.body;

  try {
    const user = await prisma.user.findUnique({ where: { id: parseInt(userId) } });

    if (!user) {
      return res.status(404).json({ error: 'User not found' });
    }

    const idea = await prisma.idea.create({
      data: {
        name,
        description,
        owner: { connect: { id: user.id } },
      },
    });

    res.json(idea);
  } catch (error) {
    console.error('Error adding idea:', error);
    res.status(500).json({ error: 'An error occurred while adding the idea' });
  }
});

app.get('/userideas/:id', async (req, res) => {
  const { id } = req.params;
  const user = await prisma.user.findUnique({
    where: { id: parseInt(id) },
    include: {
      ideas: true,
    },
  });
  if (!user) {
    return res.status(404).json({ message: 'User not found' });
  }
  res.json(user);
});

در فهرست ۶، دو نقطه پایانی داریم. اولی امکان اضافه کردن ایده با استفاده از POST در /users/:userId/ideas را می دهد. اولین کاری که باید انجام دهد این است که با استفاده از prisma.user.findUnique() کاربر را با شناسه بازیابی کند. این روش برای یافتن یک موجودیت واحد در پایگاه داده بر اساس معیارهای تصویب شده استفاده می شود. در مورد ما، کاربر را با شناسه از درخواست می‌خواهیم، ​​بنابراین از: { where: { id: parseInt(userId) } } استفاده می‌کنیم.

وقتی کاربر را داشتیم، از prisma.idea.create برای ایجاد یک idea جدید استفاده می کنیم. این درست مانند زمانی که user را ایجاد کردیم کار می کند، اما اکنون یک فیلد رابطه داریم. Prisma به ما امکان می دهد بین idea و user جدید ارتباط برقرار کنیم: owner: { connect: { id: user.id } }.< /p>

نقطه پایانی دوم یک GET در /userideas/:id است. هدف از این نقطه پایانی گرفتن شناسه کاربر و بازگرداندن کاربر شامل ایده های آنها است. این به ما نگاهی به عبارت where در استفاده با فراخوانی findUnique و همچنین اصلاح‌کننده include می‌دهد. اصلاح کننده در اینجا استفاده می شود تا به Prisma بگوید که ایده های مرتبط را در آن لحاظ کند. بدون این، ایده‌ها گنجانده نمی‌شوند، زیرا Prisma به‌طور پیش‌فرض از استراتژی واکشی بارگیری تنبل برای انجمن‌ها استفاده می‌کند.

برای آزمایش نقاط پایانی جدید، می‌توانیم از دستورات CURL نشان داده شده در فهرست ۷ استفاده کنیم.


$ curl -X POST -H "Content-Type: application/json" -d '{"name":"New Idea", "description":"Idea description"}' http://localhost:3000/users/3/ideas

$ curl http://localhost:3000/userideas/3
{"id":3,"name":"John Lennon","email":"john.lennon@example.com","ideas":[{"id":1,"name":"New Idea","description":"Idea description","ownerId":3},{"id":2,"name":"New Idea","description":"Idea description","ownerId":3}]}

ما می توانیم ایده ها را اضافه کنیم و کاربران را با آنها بازیابی کنیم.

چند به چند با برچسب

حالا اجازه دهید نقاط پایانی را برای مدیریت برچسب ها در رابطه چند به چند اضافه کنیم. در فهرست ۸، ایجاد برچسب را انجام می دهیم و یک برچسب و یک idea را به هم مرتبط می کنیم.


// create a tag
app.post('/tags', async (req, res) => {
  const { name } = req.body;

  try {
    const tag = await prisma.tag.create({
      data: {
        name,
      },
    });

    res.json(tag);
  } catch (error) {
    console.error('Error adding tag:', error);
    res.status(500).json({ error: 'An error occurred while adding the tag' });
  }
});

// Associate a tag with an idea
app.post('/ideas/:ideaId/tags/:tagId', async (req, res) => {
  const { ideaId, tagId } = req.params;

  try {
    const idea = await prisma.idea.findUnique({ where: { id: parseInt(ideaId) } });

    if (!idea) {
      return res.status(404).json({ error: 'Idea not found' });
    }

    const tag = await prisma.tag.findUnique({ where: { id: parseInt(tagId) } });

    if (!tag) {
      return res.status(404).json({ error: 'Tag not found' });
    }

    const updatedIdea = await prisma.idea.update({
      where: { id: parseInt(ideaId) },
      data: {
        tags: {
          connect: { id: tag.id },
        },
      },
    });

    res.json(updatedIdea);
  } catch (error) {
    console.error('Error associating tag with idea:', error);
    res.status(500).json({ error: 'An error occurred while associating the tag with the idea' });
  }
});

دو نقطه پایانی اضافه کرده‌ایم. نقطه پایانی POST که برای افزودن یک برچسب استفاده می‌شود، از نمونه‌های قبلی آشناست. در فهرست ۸، نقطه پایانی POST را نیز برای مرتبط کردن یک ایده با یک برچسب اضافه کرده‌ایم.

برای مرتبط کردن یک ایده و یک برچسب، از نگاشت چند به چند از تعریف مدل استفاده می‌کنیم. ما Idea و Tag را با شناسه می گیریم و از قسمت connect برای تنظیم آنها بر روی یکدیگر استفاده می کنیم. اکنون، Idea دارای شناسه Tag در مجموعه تگ‌های خود است و بالعکس. ارتباط چند به چند تا دو رابطه یک به چند را می دهد که هر موجودیت به دیگری اشاره می کند. در دیتا استور، این کار مستلزم ایجاد یک "جدول جستجو" (یا جدول مرجع متقابل) است، اما Prisma این کار را برای ما انجام می دهد. ما فقط باید با خود نهادها تعامل داشته باشیم.

آخرین مرحله برای ویژگی چند به چند ما این است که امکان یافتن ایده‌ها با برچسب و یافتن برچسب‌ها در Idea را فراهم کنیم. می توانید این قسمت از مدل را در لیست ۹ مشاهده کنید. (توجه داشته باشید که برای اختصار برخی از مدیریت خطاها را حذف کرده ام.)