شارك المقالة

لو إنت شغال بـ Node.js وبتتعامل مع قواعد بيانات زي MySQL أو PostgreSQL أو SQLite، فأكيد قابلتك مشكلة كتابة استعلامات SQL كتير ومعقدة. هنا بييجي دور Prisma، وهي واحدة من أقوى الأدوات اللي بتسهل التعامل مع قواعد البيانات داخل تطبيقات Node.js بطريقة نظيفة وسريعة وآمنة.

في المقال ده هنتعرف على Prisma في Node.js خطوة بخطوة، بداية من التثبيت، مرورًا بإنشاء الـ Models، وتشغيل الـ Migration، لحد بناء API كامل باستخدام Express و Prisma.

يعني إيه Prisma؟

Prisma هي أداة ORM حديثة بتخليك تتعامل مع قاعدة البيانات باستخدام JavaScript أو TypeScript بدل ما تكتب SQL بشكل مباشر.

يعني بدل ما تكتب استعلامات SQL طويلة ومعقدة، تقدر تستخدم Prisma Client وتتعامل مع البيانات من خلال كود بسيط وواضح.

Prisma بتدعم أكتر من نوع قاعدة بيانات، زي:

  • MySQL
  • PostgreSQL
  • SQLite
  • SQL Server
  • MongoDB

مميزات Prisma في Node.js

Prisma مش مجرد ORM عادي، لكنها Toolkit كاملة بتوفرلك تجربة مريحة جدًا أثناء التعامل مع قواعد البيانات.

  • كتابة كود أنظف وأسهل من SQL التقليدي
  • دعم قوي لـ TypeScript
  • Auto Completion ممتاز داخل VSCode
  • إدارة العلاقات بين الجداول بسهولة
  • نظام Migration لتنظيم تغييرات قاعدة البيانات
  • تقليل الأخطاء أثناء كتابة الاستعلامات

تثبيت Prisma داخل مشروع Node.js

أول حاجة لازم يكون عندك مشروع Node.js جاهز. لو لسه معندكش مشروع، تقدر تعمل واحد بالأوامر التالية:

mkdir prisma-node-app
cd prisma-node-app
npm init -y

بعد كده هنثبت Express عشان نعمل API:

npm install express

دلوقتي نثبت Prisma:

npm install prisma --save-dev
npm install @prisma/client

بعد التثبيت، نعمل تهيئة لـ Prisma داخل المشروع:

npx prisma init

الأمر ده هيعمل فولدر اسمه prisma وداخله ملف مهم جدًا اسمه:

prisma/schema.prisma

وكمان هيعمل ملف .env اللي هنحط فيه رابط الاتصال بقاعدة البيانات.

الاتصال بقاعدة البيانات باستخدام DATABASE_URL

داخل ملف .env هنضيف رابط الاتصال بقاعدة البيانات.

مثال على الاتصال بقاعدة بيانات MySQL:

DATABASE_URL="mysql://root:Aa123456!@localhost:3306/newdb"

شرح الرابط:

  • mysql: نوع قاعدة البيانات
  • root: اسم المستخدم
  • Aa123456!: كلمة المرور
  • localhost: السيرفر المحلي
  • 3306: بورت MySQL
  • newdb: اسم قاعدة البيانات

إعداد ملف schema.prisma

ملف schema.prisma هو المكان اللي بنعرف فيه الجداول والعلاقات بينهم.

مثال على ملف كامل يحتوي على جدول المستخدمين وجدول المقالات أو المنشورات:

generator client {
  provider = "prisma-client-js"
  output   = "../generated/prisma"
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

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

model Post {
  id       Int     @id @default(autoincrement())
  title    String
  content  String?
  author   User    @relation(fields: [authorId], references: [id])
  authorId Int
}

شرح Models داخل Prisma

في المثال السابق عندنا جدولين:

جدول User

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

الجدول ده بيحتوي على:

  • id: رقم المستخدم وبيزيد تلقائيًا
  • name: اسم المستخدم
  • email: البريد الإلكتروني ولازم يكون غير مكرر
  • posts: علاقة بين المستخدم والمنشورات الخاصة به

جدول Post

model Post {
  id       Int     @id @default(autoincrement())
  title    String
  content  String?
  author   User    @relation(fields: [authorId], references: [id])
  authorId Int
}

الجدول ده بيحتوي على:

  • id: رقم المنشور
  • title: عنوان المنشور
  • content: محتوى المنشور وهو اختياري بسبب علامة ?
  • authorId: رقم المستخدم صاحب المنشور
  • author: العلاقة بين المنشور والمستخدم

تشغيل Migration وإنشاء الجداول

بعد ما تكتب الـ Models داخل ملف schema.prisma، لازم تعمل Migration عشان Prisma تنشئ الجداول داخل قاعدة البيانات.

npx prisma migrate dev --name init

الأمر ده بيعمل 3 حاجات مهمة:

  • ينشئ ملفات Migration
  • ينشئ الجداول داخل قاعدة البيانات
  • يجهز Prisma Client للاستخدام داخل المشروع

ولو عدلت في ملف schema.prisma بعد كده، شغل الأمر التالي:

npx prisma generate

إنشاء ملف السيرفر باستخدام Express و Prisma

دلوقتي هننشئ ملف اسمه index.js ونبدأ نكتب API كامل للتعامل مع المستخدمين والمنشورات.

const express = require("express");
const { PrismaClient } = require("./generated/prisma");

const app = express();
app.use(express.json());

const prisma = new PrismaClient();

const PORT = 3000;

app.listen(PORT, () => {
  console.log(`الخادم يعمل على المنفذ ${PORT}`);
});

في الكود السابق عملنا:

  • استدعاء Express
  • استدعاء PrismaClient
  • تشغيل JSON Middleware
  • إنشاء Instance من Prisma
  • تشغيل السيرفر على بورت 3000

إنشاء مستخدم جديد باستخدام Prisma

هنضيف Route لإنشاء مستخدم جديد داخل قاعدة البيانات.

app.post("/user", async (req, res) => {
  const { name, email } = req.body;

  if (!name || !email) {
    return res.status(400).json({
      error: "الاسم والبريد الإلكتروني مطلوبان"
    });
  }

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

    res.status(201).json(user);
  } catch (error) {
    if (error.code === "P2002") {
      return res.status(409).json({
        error: "البريد الإلكتروني مكرر"
      });
    }

    res.status(500).json({
      error: "خطأ في إنشاء المستخدم"
    });
  }
});

في الكود ده بنعمل الآتي:

  • بنستقبل name و email من body
  • بنتأكد إن البيانات موجودة
  • بنستخدم prisma.user.create لإنشاء مستخدم جديد
  • لو البريد الإلكتروني مكرر، Prisma بترجع error code اسمه P2002

جلب المستخدمين والبحث بالاسم

ممكن نعمل Route للبحث عن المستخدمين باستخدام الاسم.

app.get("/user", async (req, res) => {
  const { name } = req.body;

  try {
    const user = await prisma.user.findMany({
      where: {
        name: {
          contains: name,
        },
      },
    });

    res.status(200).json(user);
  } catch (error) {
    res.status(500).json({
      error: "خطأ في جلب المستخدمين"
    });
  }
});

استخدمنا هنا findMany لأنها بترجع أكتر من مستخدم.

واستخدمنا contains عشان نبحث عن أي اسم يحتوي على النص المرسل.

إنشاء منشور جديد وربطه بالمستخدم

دلوقتي هنضيف Route لإنشاء منشور جديد، ولازم المنشور يكون مرتبط بمستخدم موجود بالفعل.

app.post("/post", async (req, res) => {
  const { title, content, authorId } = req.body;

  if (!title || !authorId) {
    return res.status(400).json({
      error: "العنوان ورقم المؤلف مطلوبان"
    });
  }

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

    if (!user) {
      return res.status(404).json({
        error: "المستخدم غير موجود"
      });
    }

    const newPost = await prisma.post.create({
      data: {
        title,
        content: content || null,
        authorId,
      },
    });

    res.status(201).json({
      message: "تم إنشاء المنشور بنجاح",
      post: newPost,
    });
  } catch (error) {
    console.error("خطأ في إنشاء المنشور:", error);

    res.status(500).json({
      error: "حدث خطأ داخلي في الخادم"
    });
  }
});

في المثال ده عملنا خطوة مهمة جدًا، وهي التحقق من وجود المستخدم قبل إنشاء المنشور.

وده بيمنع إننا نضيف Post مرتبط بـ User غير موجود داخل قاعدة البيانات.

جلب المنشورات مع بيانات المؤلف

Prisma بتسهل جدًا جلب البيانات المرتبطة ببعض.

مثلاً لو عايز تجيب كل المنشورات ومعاها بيانات المستخدم صاحب كل منشور، تقدر تستخدم include.

app.get("/posts", async (req, res) => {
  try {
    const posts = await prisma.post.findMany({
      include: {
        author: true,
      },
    });

    res.json(posts);
  } catch (error) {
    console.error("خطأ في جلب المنشورات:", error);

    res.status(500).json({
      error: "فشل جلب البيانات"
    });
  }
});

استخدام include هنا معناه إن Prisma هترجع المنشورات ومعاها بيانات المؤلف المرتبط بكل منشور.

المثال الكامل لاستخدام Prisma مع Node.js

const express = require("express");
const { PrismaClient } = require("./generated/prisma");

const app = express();
app.use(express.json());

const prisma = new PrismaClient();

app.post("/post", async (req, res) => {
  const { title, content, authorId } = req.body;

  if (!title || !authorId) {
    return res.status(400).json({
      error: "العنوان ورقم المؤلف مطلوبان"
    });
  }

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

    if (!user) {
      return res.status(404).json({
        error: "المستخدم غير موجود"
      });
    }

    const newPost = await prisma.post.create({
      data: {
        title,
        content: content || null,
        authorId,
      },
    });

    res.status(201).json({
      message: "تم إنشاء المنشور بنجاح",
      post: newPost,
    });
  } catch (error) {
    console.error("خطأ في إنشاء المنشور:", error);

    res.status(500).json({
      error: "حدث خطأ داخلي في الخادم"
    });
  }
});

app.get("/posts", async (req, res) => {
  try {
    const posts = await prisma.post.findMany({
      include: {
        author: true,
      },
    });

    res.json(posts);
  } catch (error) {
    console.error("خطأ في جلب المنشورات:", error);

    res.status(500).json({
      error: "فشل جلب البيانات"
    });
  }
});

app.post("/user", async (req, res) => {
  const { name, email } = req.body;

  if (!name || !email) {
    return res.status(400).json({
      error: "الاسم والبريد الإلكتروني مطلوبان"
    });
  }

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

    res.status(201).json(user);
  } catch (error) {
    if (error.code === "P2002") {
      return res.status(409).json({
        error: "البريد الإلكتروني مكرر"
      });
    }

    res.status(500).json({
      error: "خطأ في إنشاء المستخدم"
    });
  }
});

app.get("/user", async (req, res) => {
  const { name } = req.body;

  try {
    const user = await prisma.user.findMany({
      where: {
        name: {
          contains: name,
        },
      },
    });

    res.status(200).json(user);
  } catch (error) {
    res.status(500).json({
      error: "خطأ في جلب المستخدمين"
    });
  }
});

const PORT = 3000;

app.listen(PORT, () => {
  console.log(`الخادم يعمل على المنفذ ${PORT}`);
});

أهم أوامر Prisma التي هتحتاجها

دي مجموعة من أهم أوامر Prisma اللي هتستخدمها كتير أثناء الشغل:

npx prisma init

لتهيئة Prisma داخل المشروع.

npx prisma migrate dev --name init

لإنشاء Migration وتطبيق التغييرات على قاعدة البيانات.

npx prisma generate

لتوليد Prisma Client بعد تعديل ملف schema.

npx prisma studio

لفتح واجهة رسومية تقدر من خلالها تشوف وتعدل البيانات الموجودة في قاعدة البيانات.

استخدام Prisma Studio

واحدة من المميزات الجميلة في Prisma هي أداة Prisma Studio.

الأداة دي بتفتحلك واجهة بسيطة في المتصفح تقدر من خلالها تشوف الجداول والبيانات وتضيف أو تعدل أو تحذف Records بسهولة.

npx prisma studio

بعد تشغيل الأمر، هيفتح معاك رابط في المتصفح لإدارة البيانات بشكل مرئي.

إضافة Prisma Insider في VSCode

لو عايز تجربة أفضل أثناء كتابة ملفات Prisma داخل VSCode، تقدر تستخدم إضافة:

Prisma – Insider

الإضافة دي بتساعدك في:

  • تنسيق ملفات .prisma تلقائيًا
  • تكميل ذكي للكود
  • اكتشاف الأخطاء أثناء الكتابة
  • تحسين تجربة العمل مع Prisma داخل VSCode

وتقدر تضيف الإعدادات التالية داخل ملف settings.json في VSCode:

{
  "[prisma]": {
    "editor.defaultFormatter": "Prisma.prisma-insider",
    "editor.formatOnSave": true
  }
}

بعد كده أي ملف .prisma هيتفرمت تلقائيًا عند الحفظ.

الفرق بين Prisma وكتابة SQL مباشرة

PrismaSQL مباشر
كود أبسط وأسهلاستعلامات أطول
يدعم Type Safetyأخطاء أكثر أثناء الكتابة
إدارة العلاقات سهلةتحتاج JOIN يدوي
Migration منظمةتحتاج إدارة يدوية

أفضل استخدامات Prisma

تقدر تستخدم Prisma في مشاريع كتير، زي:

  • REST APIs باستخدام Express
  • تطبيقات Next.js
  • لوحات التحكم Admin Dashboards
  • أنظمة تسجيل الدخول والمستخدمين
  • المتاجر الإلكترونية
  • تطبيقات إدارة المحتوى

نصائح مهمة عند استخدام Prisma

  • متنساش تشغل npx prisma generate بعد أي تعديل في schema
  • استخدم @unique مع الحقول اللي مينفعش تتكرر زي البريد الإلكتروني
  • استخدم include لما تحتاج تجيب بيانات العلاقات
  • استخدم Prisma Studio لمراجعة البيانات بسرعة
  • خلي بيانات الاتصال بقاعدة البيانات داخل ملف .env

الخلاصة

Prisma تعتبر واحدة من أفضل الأدوات للتعامل مع قواعد البيانات في مشاريع Node.js، لأنها بتوفر طريقة سهلة وآمنة وسريعة بدل كتابة SQL بشكل يدوي.

من خلال Prisma تقدر تعرف الجداول داخل ملف schema.prisma، وتعمل Migration، وتستخدم Prisma Client لإضافة وتعديل وحذف وجلب البيانات بكل سهولة.

ولو إنت بتبني API باستخدام Express، فـ Prisma هتساعدك جدًا في تنظيم الكود وتقليل الأخطاء وتسريع عملية التطوير.

ببساطة، لو شغال بـ Node.js وعايز تتعامل مع قاعدة البيانات بشكل احترافي، يبقى Prisma اختيار ممتاز جدًا.


مزيد من المقالات : كيفية تقليل حجم مشاريع Flutter على جهازك
شاهد أيضًا
مقالات ذات صلة

🚫 مانع الإعلانات مفعل

يجب إيقاف مانع الإعلانات لاستكمال تصفح الموقع