العمل مع قواعد البيانات في Rust: PostgreSQL و MongoDB عملياً

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا يعتبر Rust وقواعد البيانات مزيجاً قوياً

Rust هي لغة برمجة نظامية تجمع بين أداء C/C++ وأمان الذاكرة. ومع ذلك، لفترة طويلة، كانت بيئة العمل مع قواعد البيانات في Rust تُعتبر "غير ناضجة". اليوم تغير الوضع جذرياً: المكتبات sqlx (لـ PostgreSQL) والمشغل الرسمي mongodb توفر واجهات برمجة تطبيقات ناضجة وغير متزامنة وآمنة.

في هذه المقالة، سنشرح عملياً كيفية الاتصال بـ PostgreSQL و MongoDB من Rust، وتنفيذ عمليات CRUD ومعالجة الأخطاء. جميع الأمثلة ستستخدم بيئة التشغيل غير المتزامنة tokio.



1. إعداد المشروع وتثبيت التبعيات

أنشئ مشروع Cargo جديد:

cargo new rust_db_examplecd rust_db_example

أضف التبعيات التالية إلى Cargo.toml:

[dependencies]tokio = { version = "1", features = ["full"] }sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "postgres"] }mongodb = "2.8"serde = { version = "1", features = ["derive"] }anyhow = "1"
  • sqlx — مشغل غير متزامن لـ PostgreSQL مع التحقق من الاستعلامات في وقت الترجمة.
  • mongodb — المشغل الرسمي من MongoDB Inc.
  • serde — للتسلسل/إلغاء التسلسل للهياكل.
  • anyhow — لمعالجة الأخطاء بسهولة.


2. العمل مع PostgreSQL عبر sqlx

2.1 الاتصال بقاعدة البيانات

للاتصال، استخدم سلسلة الاتصال (connection string) بالشكل postgres://user:password@localhost/dbname. مثال:

use sqlx::postgres::PgPool;use anyhow::Result;

#[tokio::main]async fn main() -> Result<()> { let pool = PgPool::connect("postgres://postgres:password@localhost/testdb").await?; println!("تم إنشاء الاتصال بـ PostgreSQL!"); Ok(())}


2.2 إنشاء جدول وإدراج البيانات

سنعرف الهيكل User وننفذ الترحيل:

use serde::{Deserialize, Serialize};use sqlx::FromRow;

#[derive(Debug, Serialize, Deserialize, FromRow)]struct User { id: i32, name: String, email: String,}

async fn create_table(pool: &PgPool) -> Result<()> { sqlx::query( "CREATE TABLE IF NOT EXISTS users ( id SERIAL PRIMARY KEY, name VARCHAR(255) NOT NULL, email VARCHAR(255) NOT NULL UNIQUE )" ) .execute(pool) .await?; println!("تم إنشاء جدول users"); Ok(())}

async fn insert_user(pool: &PgPool, name: &str, email: &str) -> Result<User> { let user = sqlx::query_as::<_, User>( "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id, name, email" ) .bind(name) .bind(email) .fetch_one(pool) .await?; Ok(user)}

لاحظ استخدام $1, $2 — هذه استعلامات مع معلمات تحمي من هجمات SQL injection.



2.3 قراءة وتحديث البيانات

async fn get_user_by_email(pool: &PgPool, email: &str) -> Result<Option<User>> {    let user = sqlx::query_as::<_, User>("SELECT * FROM users WHERE email = $1")        .bind(email)        .fetch_optional(pool)        .await?;    Ok(user)}

async fn update_user_name(pool: &PgPool, id: i32, new_name: &str) -> Result<()> { sqlx::query("UPDATE users SET name = $1 WHERE id = $2") .bind(new_name) .bind(id) .execute(pool) .await?; println!("تم تحديث المستخدم {}", id); Ok(())}

استخدام fetch_optional يسمح بمعالجة حالة عدم العثور على السجل دون حدوث ذعر (panic).



3. العمل مع MongoDB عبر المشغل الرسمي

3.1 الاتصال واختيار قاعدة البيانات

المدونات

توصيات الكتب