0Pricing
Learn Rust Coding · درس

تكامل قواعد البيانات (SQLx/Diesel)

ادمجوا خدمة الويب المبنية بلغة Rust مع قواعد البيانات باستخدام ORM شائعة أو أدوات بناء الاستعلامات مثل SQLx أو Diesel.

تكامل قواعد البيانات (SQLx/Diesel) درس مجاني في Learn Rust Coding على CoddyKit. هذا هو الدرس 2 من أصل 3. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Learn Rust Coding، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Learn Rust Coding 3 دروس في المجموع.

لماذا نستخدم قواعد البيانات للويب؟

غالبًا ما تحتاج خدمات الويب إلى تخزين البيانات واستردادها بشكل دائم. فكروا في ملفات تعريف المستخدمين، أو فهارس المنتجات، أو منشورات المدونات؛ إذ يجب أن تبقى هذه البيانات في مكان يتجاوز ذاكرة برنامجكم.

توفر قواعد البيانات طريقة منظمة لإدارة هذه البيانات، مع ضمان أمانها واتساقها وإمكانية الوصول إليها. ويُعد دمج خدمة الويب المكتوبة بلغة Rust مع قاعدة بيانات مهمة أساسية في معظم التطبيقات الواقعية.

SQLx: رفيقكم في قواعد البيانات غير المتزامنة

لدينا في Rust أدوات ممتازة للتفاعل مع قواعد البيانات. ومن الخيارين الشائعين SQLx وDiesel.

  • SQLx: حزمة SQL غير متزامنة ومكتوبة بالكامل بلغة Rust، مع استعلامات يجري التحقق منها وقت الترجمة. وغالبًا ما تُفضّل لخدمات الويب غير المتزامنة المبنية باستخدام أطر مثل Tokio.
  • Diesel: أداة ORM (مُطابق الكائنات العلائقية) قوية توفر طريقة أكثر تجريدًا للتفاعل مع قاعدة البيانات، إذ تطابق بنيات Rust مباشرةً مع جداول قاعدة البيانات. وعادةً ما تكون متزامنة.

سنركز في هذا الدرس على SQLx لدعمه القوي للبرمجة غير المتزامنة، بما يتوافق جيدًا مع تطوير خدمات الويب الحديثة باستخدام Rust.

إعداد SQLx: التبعيات

قبل كتابة التعليمات البرمجية، يجب إضافة sqlx وtokio إلى Cargo.toml الخاص بمشروعكم. يوفر tokio بيئة التشغيل غير المتزامنة التي يحتاج إليها sqlx.

على سبيل المثال، لاستخدام SQLite (وهي قاعدة بيانات سهلة قائمة على الملفات ومناسبة للتطوير المحلي) مع SQLx، قد يبدو ملف Cargo.toml لديكم كما يلي:

[dependencies] sqlx = { version = "0.7", features = ["runtime-tokio-rustls", "sqlite"] } tokio = { version = "1", features = ["full"] }

ستستخدمون عادةً أيضًا متغير البيئة DATABASE_URL لإعداد سلسلة اتصال قاعدة البيانات.

الاتصال بأولى قواعد بياناتكم

لنع establish اتصالًا بقاعدة بيانات SQLite موجودة في الذاكرة. يستخدم SQLx مجمعات الاتصالات التي تدير عدة اتصالات بقاعدة البيانات بكفاءة للتعامل مع الطلبات المتزامنة في خدمة الويب الخاصة بكم.

جرّبوا تشغيل هذا المثال:

use sqlx::SqlitePool;
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    // Use an in-memory SQLite database for simplicity
    let database_url = "sqlite::memory:"; 
    let pool = SqlitePool::connect(&database_url).await?;
    println!("Successfully connected to the database!");

    // In a real web app, 'pool' would be passed around or stored in app state.

    Ok(())
}

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

قبل أن نتمكن من تخزين البيانات، نحتاج إلى تعريف مخطط قاعدة البيانات باستخدام DDL (لغة تعريف البيانات). لننشئ جدول tasks بسيطًا.

تسمح لكم الوحدة الماكرو sqlx::query! بتضمين SQL مباشرةً في تعليمات Rust البرمجية. كما أنها تجري فحوصات على SQL وقت الترجمة!

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    // Create a 'tasks' table if it doesn't exist
    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    println!("Table 'tasks' created successfully!");
    Ok(())
}

إضافة سجلات جديدة

بعد أن أصبح لدينا جدول، لنضف بعض البيانات! سنستخدم عبارة INSERT مع ربط المعلمات. يحمي ذلك من حقن SQL ويجعل استعلاماتكم أكثر أمانًا.

لاحظوا استخدام العناصر النائبة ? للمعلمات، وتمرير القيم إلى .bind().

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    // Insert a new task
    let description = "Learn SQLx";
    let completed = false;
    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        description,
        completed
    ).execute(&pool).await?;

    println!("Task '{}' inserted successfully!", description);
    Ok(())
}

استرداد البيانات باستخدام SELECT

لجلب البيانات من جدول tasks، نستخدم عبارة SELECT. يوفر SQLx أساليب مثل .fetch_all() أو .fetch_one() للحصول على النتائج.

يمكنكم التكرار على الصفوف المُعادة والوصول إلى الأعمدة باستخدام الاسم أو الفهرس.

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Learn SQLx", false
    ).execute(&pool).await?;
    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Build a web app", false
    ).execute(&pool).await?;

    // Fetch and print all tasks
    println!("\n--- All Tasks ---");
    let rows = query!("SELECT id, description, completed FROM tasks")
        .fetch_all(&pool).await?;

    for row in rows {
        println!("ID: {}, Desc: {}, Done: {}", 
            row.id, row.description, row.completed);
    }
    Ok(())
}

بيانات آمنة نوعيًا باستخدام البنى

قد يكون استخراج البيانات من الصفوف يدويًا عرضةً للأخطاء. تتيح لكم الوحدة الماكرو query_as! في SQLx، مع #[derive(FromRow)]، مطابقة نتائج الاستعلام مباشرةً مع بنيات Rust!

يوفر ذلك أمانًا قويًا للأنواع ويجعل التعليمات البرمجية أنظف وأسهل بكثير في التعامل معها.

use sqlx::{FromRow, SqlitePool, query, query_as};
use tokio;

#[derive(Debug, FromRow)]
struct Task {
    id: i64,
    description: String,
    completed: bool,
}

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Learn SQLx", false
    ).execute(&pool).await?;

    // Fetch tasks directly into our Task struct
    println!("\n--- Tasks as Structs ---");
    let tasks = query_as::<_, Task>("SELECT id, description, completed FROM tasks")
        .fetch_all(&pool).await?;

    for task in tasks {
        println!("{:?}", task);
    }
    Ok(())
}

تعديل السجلات وحذفها

يتبع تحديث البيانات وحذفها نمطًا مشابهًا لإدراجها. تستخدمون عبارات SQL من نوعي UPDATE وDELETE مع ربط المعلمات.

  • UPDATE: يغيّر الصفوف الموجودة استنادًا إلى عبارة WHERE.
  • DELETE: يحذف الصفوف استنادًا إلى عبارة WHERE.

احرصوا دائمًا عند استخدام عبارات WHERE مع UPDATE وDELETE لتجنب فقدان البيانات غير المقصود!

use sqlx::{SqlitePool, query};
use tokio;

#[tokio::main]
async fn main() -> Result<(), sqlx::Error> {
    let database_url = "sqlite::memory:";
    let pool = SqlitePool::connect(&database_url).await?;

    query!(
        "CREATE TABLE IF NOT EXISTS tasks (
            id INTEGER PRIMARY KEY AUTOINCREMENT,
            description TEXT NOT NULL,
            completed BOOLEAN NOT NULL DEFAULT FALSE
        )"
    ).execute(&pool).await?;

    query!(
        "INSERT INTO tasks (description, completed) VALUES (?, ?)",
        "Finish lesson", false
    ).execute(&pool).await?;
    let task_id_to_update = 1;

    // Update a task
    query!(
        "UPDATE tasks SET completed = ? WHERE id = ?",
        true,
        task_id_to_update
    ).execute(&pool).await?;
    println!("Task {} updated.", task_id_to_update);

    // Delete a task (uncomment to run, careful with IDs after update)
    // let task_id_to_delete = 1;
    // query!(
    //     "DELETE FROM tasks WHERE id = ?",
    //     task_id_to_delete
    // ).execute(&pool).await?;
    // println!("Task {} deleted.", task_id_to_delete);

    Ok(())
}

اختبروا مهاراتكم في قواعد البيانات

أي العبارات التالية صحيحة بشأن SQLx في خدمات الويب المكتوبة بلغة Rust؟

تكامل قواعد البيانات: أهم النقاط

لقد خطوتم خطوة مهمة نحو إنشاء خدمات ويب متينة باستخدام Rust من خلال تعلم تكامل قواعد البيانات!

  • الاستمرارية: قواعد البيانات ضرورية لتخزين بيانات التطبيقات.
  • SQLx: حزمة SQL غير متزامنة يجري التحقق منها وقت الترجمة، وهي مناسبة جدًا لخدمات الويب.
  • مجمعات الاتصالات: ضرورية للوصول الفعال والمتزامن إلى قاعدة البيانات.
  • CRUD: غطينا إنشاء البيانات (INSERT) واستردادها (SELECT) وتحديثها (UPDATE) وحذفها (DELETE).
  • أمان الأنواع: تتيح query_as! و#[derive(FromRow)] مطابقة البيانات بأمان وسهولة.

يمكنكم الآن استكشاف دمج عمليات قاعدة البيانات هذه في مسارات ويب فعلية!

الأسئلة الشائعة

هل درس «تكامل قواعد البيانات (SQLx/Diesel)» مجاني؟

نعم — نص درس «تكامل قواعد البيانات (SQLx/Diesel)» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Learn Rust Coding، انتقل إلى CoddyKit PRO. تتضمن دورة Learn Rust Coding 3 دروس في المجموع.

ماذا ستتعلم في «تكامل قواعد البيانات (SQLx/Diesel)»؟

ادمجوا خدمة الويب المبنية بلغة Rust مع قواعد البيانات باستخدام ORM شائعة أو أدوات بناء الاستعلامات مثل SQLx أو Diesel. تتمرن على Learn Rust Coding مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Learn Rust Coding؟

لا تُشترط خبرة سابقة. Learn Rust Coding على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 3.

كم من الوقت يستغرق درس «تكامل قواعد البيانات (SQLx/Diesel)»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Learn Rust Coding هذا؟

نعم. كل درس في Learn Rust Coding يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. واجهات REST البرمجية باستخدام Actix-web/Rocket
  2. تكامل قواعد البيانات (SQLx/Diesel)
  3. المصادقة والتفويض
← العودة إلى Learn Rust Coding