NahdaAIنهضة
Supabase • المستوى الثالث • الدرس 2

قاعدة البيانات العلاقلية والأمان (Postgres + RLS)

العودة لفهرس المستوى

أهداف الدرس

  • CRUD كامل: select, insert, update, delete.
  • الفلاتر: eq, gte, order, limit.
  • الفهم الأساسي لـ Row Level Security (RLS).
  • الاستعلامات الآمنة والأداء العالي.

1. Supabase Database — نظرة عامة

Supabase يعطيك قاعدة بيانات PostgreSQL كاملة، لكن مع واجهة JavaScript بسيطة تشبه ORM خفيف. يمكنك استخدام:

  • • الطريقة الكاملة: supabase.from('table').select() (هي التي سنتعلمها).
  • • الطريقة المباشرة: SQL عبر supabase.rpc() أو psql.
javascript
// طريقة Supabase للاستعلامات
// from() → select() → filters → single()
const { data, error } = await supabase
  .from('users')       // المجموعة / الجدول
  .select('*')         // الأعمدة
  .eq('age', 25)       // فلتر
  .order('name');      // ترتيب

2. القراءة — select

select() هي نقطة البداية لأي قراءة. يمكنك تحديد الأعمدة أو استخدام *:

javascript
// كل الأعمدة
await supabase.from('users').select('*');

// أعمدة محددة
await supabase.from('users').select('name, age');

// مع جدول مرتبط (Foreign Table)
await supabase
  .from('orders')
  .select('id, total, users(name, email)');

// مع عدّاد
await supabase
  .from('users')
  .select('*', { count: 'exact' });

3. الفلاتر — eq, gte, order, limit

بعد select()، يمكنك إضافة سلسلة من الفلاتر (Method Chaining):

eq

مساواة دقيقة.

.eq('id', 5)
gte

أكبر أو يساوي.

.gte('age', 18)
order

ترتيب النتائج.

.order('age', { ascending: false })
limit

تحديد العدد.

.limit(5)
javascript
// استعلام مركب
const { data, error } = await supabase
  .from('users')
  .select('name, age')
  .gte('age', 18)
  .order('age', { ascending: false })
  .limit(5);

// فلاتر أخرى شائعة:
// .lte()   — أصغر أو يساوي
// .gt()    — أكبر من
// .lt()    — أصغر من
// .neq()   — لا يساوي
// .like()  — مطابقة نمط
// .in()    — ضمن قائمة
// .is()    — للـ NULL

4. الإدراج والتحديث والحذف

insert

إدراج صف أو عدة صفوف.

await supabase
  .from('users')
  .insert([{ name, email }]);
update

تحديث صفوف (يحتاج .eq لتفادي تحديث الكل).

await supabase
  .from('users')
  .update({ age: 30 })
  .eq('id', 5);
delete

حذف صفوف (يحتاج .eq).

await supabase
  .from('users')
  .delete()
  .eq('id', 5);
single

جلب صف واحد فقط (يُعيد كائناً لا مصفوفة).

await supabase
  .from('users')
  .select('*')
  .eq('id', 5)
  .single();
تحذير أمني
await supabase.from('users').delete();  // يحذف كل شيء!

في Supabase، delete() بدون .eq = مسح كامل. دائماً استخدم .eq أو فلتراً.

5. Row Level Security (RLS)

RLS هي طبقة أمان على مستوى الصف في Postgres. تُتيح لك تحديد: من يمكنه قراءة أي صف، من يمكنه تعديله، من يمكنه حذفه.

مثال Policy
-- كل مستخدم يقرأ بياناته فقط
CREATE POLICY "Users can read own data"
ON users FOR SELECT
USING (auth.uid() = user_id);

-- كل مستخدم يعدّل بياناته فقط
CREATE POLICY "Users can update own data"
ON users FOR UPDATE
USING (auth.uid() = user_id);
  • • auth.uid() — يُرجع UID المستخدم الحالي
  • • USING — الشرط للقراءة/التحديث
  • • WITH CHECK — الشرط للإدراج/التحديث الجديد
sql
-- مثال شامل: جدول messages
CREATE TABLE messages (
  id BIGSERIAL PRIMARY KEY,
  user_id UUID REFERENCES auth.users(id),
  content TEXT NOT NULL,
  created_at TIMESTAMPTZ DEFAULT NOW()
);

-- RLS: لا يمكن قراءة إلا رسائل المستخدم
ALTER TABLE messages ENABLE ROW LEVEL SECURITY;

CREATE POLICY "Users see own messages"
ON messages FOR SELECT
USING (auth.uid() = user_id);

CREATE POLICY "Users insert own messages"
ON messages FOR INSERT
WITH CHECK (auth.uid() = user_id);
التطبيق العملي

تحدي الدرس: CRUD كامل لجدول users

  1. أضف createUser مع insert.
  2. أضف updateUserAge مع update().eq().
  3. أضف deleteUser مع delete().eq().
  4. أضف getAdults مع gte + order + limit.
  5. أضف getUserById مع single().
  6. أضف اختباراً تلقائياً.
⏳ جارٍ التحميل...