لماذا يتعاون JavaScript مع PostgreSQL؟
\n\nإذا كنت تكتب بلغة JavaScript (خاصة على Node.js) وما زلت تستخدم MySQL أو، لا سمح الله، SQLite في الإنتاج، فأنت تخسر المال والأعصاب. PostgreSQL ليست مجرد "قاعدة بيانات أخرى". إنها سكين سويسري للبيانات تعرف كل شيء: من JOIN المعقدة إلى مستندات JSON، والبحث النصي الكامل، والاستعلامات الجغرافية. والتركيبة JavaScript + PostgreSQL هي المعيار الحديث لتطبيقات الويب، والخدمات المصغرة، والتحليلات.
\n\nفي هذا الدليل، سنشرح كل ما يحتاج مطور Node.js معرفته: من تثبيت المشغل إلى المعاملات، والترحيلات، والتحسين. لا ماء - فقط كود وتطبيق عملي.
\n\nالخطوة 1: تثبيت وتهيئة مشغل pg
\n\nللعمل مع PostgreSQL من JavaScript، يُستخدم الحزمة pg - العميل الرسمي. يتم تثبيته في ثانية:
npm install pg\n\nالآن ننشئ اتصالاً. هناك طريقتان: Client (اتصال واحد) و Pool (مجموعة اتصالات). للإنتاج، استخدم دائماً Pool - فهو يدير إعادة استخدام الاتصالات ولا يثقل قاعدة البيانات عند التحميل.
\n\nconst { Pool } = require('pg');\n\nconst pool = new Pool({\n user: 'your_user',\n host: 'localhost',\n database: 'your_db',\n password: 'your_password',\n port: 5432,\n max: 20, // أقصى عدد اتصالات في المجموعة\n idleTimeoutMillis: 30000,\n connectionTimeoutMillis: 2000,\n});\n\n// اختبار الاتصال\npool.query('SELECT NOW()')\n .then(res => console.log('✅ متصل:', res.rows[0].now))\n .catch(err => console.error('❌ خطأ:', err));\n\nهام: لا تقم أبداً بتضمين كلمات المرور في الكود. استخدم متغيرات البيئة (process.env.DATABASE_URL) أو مدير الأسرار.
الخطوة 2: CRUD - الأساسيات
\n\nأي تطبيق يبدأ بـ CRUD (إنشاء، قراءة، تحديث، حذف). سنشرح كل عملية على JavaScript مع PostgreSQL.
\n\nإنشاء جدول (DDL)
\n\nconst createTable = async () => {\n const query = `\n CREATE TABLE IF NOT EXISTS users (\n id SERIAL PRIMARY KEY,\n name VARCHAR(100) NOT NULL,\n email VARCHAR(255) UNIQUE NOT NULL,\n age INTEGER CHECK (age > 0),\n created_at TIMESTAMP DEFAULT NOW()\n );\n `;\n await pool.query(query);\n console.log('✅ تم إنشاء جدول users');\n};\n\ncreateTable();\n\nINSERT - إضافة البيانات
\n\nconst addUser = async (name, email, age) => {\n // استخدام استعلام مع معلمات - حماية من حقن SQL!\n const query = `\n INSERT INTO users (name, email, age)\n VALUES ($1, $2, $3)\n RETURNING *;\n `;\n const values = [name, email, age];\n const res = await pool.query(query, values);\n console.log('✅ تمت إضافة المستخدم:', res.rows[0]);\n return res.rows[0];\n};\n\n// مثال على الاستدعاء\naddUser('آنا بيتروفا', 'anna@example.com', 28);\n\nSELECT - القراءة مع التصفية
\n\nconst getUsers = async (minAge = 0) => {\n const query = 'SELECT * FROM users WHERE age > $1 ORDER BY created_at DESC';\n const res = await pool.query(query, [minAge]);\n console.log(`📊 تم العثور على مستخدمين: ${res.rowCount}`);\n return res.rows;\n};\n\ngetUsers(25).then(users => console.log(users));\n\nUPDATE - تحديث سجل
\n\nconst updateUserEmail = async (id, newEmail) => {\n const query = `\n UPDATE users\n SET email = $2, updated_at = NOW()\n WHERE id = $1\n RETURNING *;\n `;\n const res = await pool.query(query, [id, newEmail]);\n if (res.rowCount === 0) {\n console.log('⚠️ لم يتم العثور على المستخدم');\n return null;\n }\n console.log('✅ تم تحديث البريد الإلكتروني:', res.rows[0]);\n return res.rows[0];\n};\n\nDELETE - الحذف
\n\nconst deleteUser = async (id) => {\n const query = 'DELETE FROM users WHERE id = $1 RETURNING *';\n