انتقل إلى المحتوى

إنشاء SQL

يحوّل SqlGenerator ‏MergeResult إلى عبارات SQL ذات معلمات. تُمرر جميع القيم على هيئة معلمات، ولا تُدرج مباشرةً في سلسلة SQL.

PHP
use Merql\Apply\SqlGenerator;

$statements = SqlGenerator::generate($result);

foreach ($statements as $stmt) {
    echo $stmt['sql'] . "\n";
    // INSERT INTO `posts` (`id`, `title`, `status`) VALUES (?, ?, ?)
    print_r($stmt['params']);
    // [42, 'New Title', 'publish']
}

استخدم generateGuarded() عندما ينبغي ألا تُطبّق خطة دمج تمت مراجعتها إلا إذا كانت الصفوف الحية ما تزال تطابق لقطة متوقعة.

PHP
use Merql\Apply\SqlGenerator;
use Merql\Snapshot\SnapshotStore;

$statements = SqlGenerator::generateGuarded(
    $selectedResult,
    SnapshotStore::load('theirs'),
);

تنسيق العبارة

كل عبارة مصفوفة ترابطية ذات مفتاحين:

PHP
[
    'sql'    => 'INSERT INTO `posts` (`id`, `title`) VALUES (?, ?)',
    'params' => [42, 'New Title'],
]

تُقتبس المعرّفات (أسماء الجداول والأعمدة) وفق أسلوب الاقتباس في برنامج تشغيل قاعدة البيانات. يستخدم MySQL علامات backtick، بينما يستخدم SQLite علامتي اقتباس مزدوجتين. وعند عدم توفير برنامج تشغيل، تُستخدم علامات backtick افتراضيًا.

ترتيب العمليات

تُجمّع العمليات حسب النوع وتُنفّذ بهذا الترتيب:

  1. عمليات INSERT أولًا -- يجب أن توجد الصفوف الجديدة قبل أن تشير إليها التحديثات.
  2. عمليات UPDATE ثانيًا.
  3. عمليات DELETE أخيرًا -- يجب إزالة المراجع إلى الصفوف قبل حذفها.
PHP
$statements = SqlGenerator::generate($result);
// All INSERTs, then all UPDATEs, then all DELETEs.

ترتيب المفاتيح الخارجية

عند توفير تبعيات المفاتيح الخارجية، تُرتّب العمليات داخل كل مجموعة ترتيبًا طوبولوجيًا. وتُعالج الجداول الأصلية قبل الجداول التابعة في عمليات الإدراج والتحديث، والجداول التابعة قبل الأصلية في عمليات الحذف.

PHP
$fkDependencies = [
    'comments' => ['posts'],        // comments references posts
    'post_meta' => ['posts'],       // post_meta references posts
];

$statements = SqlGenerator::generate($result, fkDependencies: $fkDependencies);
// INSERTs: posts first, then comments and post_meta
// DELETEs: comments and post_meta first, then posts

يجري ForeignKeyResolver ترتيبًا طوبولوجيًا على رسم التبعيات. وتُكتشف التبعيات الدائرية وتُكسر لمنع الحلقات اللانهائية.

الكشف التلقائي عن المفاتيح الخارجية

يقرأ Applier علاقات المفاتيح الخارجية تلقائيًا من قاعدة البيانات:

PHP
use Merql\Apply\Applier;

$applier = new Applier($connection);
$applied = $applier->apply($result);
// FK dependencies are read from the database via the driver.

أمثلة على SQL المُنشأة

INSERT

Sql
INSERT INTO `posts` (`id`, `title`, `content`, `status`) VALUES (?, ?, ?, ?)
-- params: [42, 'New Post', 'Body text', 'draft']

تُضمّن جميع الأعمدة من قيم العملية.

UPDATE

Sql
UPDATE `posts` SET `title` = ?, `status` = ? WHERE `id` = ?
-- params: ['New Title', 'publish', 42]

تُستبعد أعمدة الهوية (المفتاح الأساسي) من بند SET وتُستخدم في بند WHERE. وتُستخرج قيم بند WHERE من فك ترميز مفتاح الصف.

DELETE

Sql
DELETE FROM `posts` WHERE `id` = ?
-- params: [42]

لا تظهر في بند WHERE إلا أعمدة الهوية.

UPDATE محمي

تتضمن التحديثات المحمية بنودًا للهوية وبنودًا للصف الحي المتوقع.

Sql
UPDATE `posts` SET `title` = ? WHERE `id` = ? AND `status` = ?
-- params: ['New Title', 42, 'draft']

إذا لم يعد الصف يحمل status المتوقع، فلن تؤثر العبارة في أي صف، وسيلغي التطبيق المحمي المعاملة.

INSERT محمي

تستخدم عمليات الإدراج المحمية NOT EXISTS لتجنب الإدراج بهوية ظهرت بعد إنشاء الخطة.

Sql
INSERT INTO `posts` (`id`, `title`) SELECT ?, ? WHERE NOT EXISTS (
  SELECT 1 FROM `posts` WHERE `id` = ?
)
-- params: [42, 'New Post', 42]

التعامل مع NULL

تُمرر قيم NULL بوصفها PHP ‏null في مصفوفة params. ويتولى محوّل الاتصال ربطها:

PHP
$statements = SqlGenerator::generate($result);
// params might contain: [42, null, 'draft']
// The adapter binds null as SQL NULL

في مخرجات التشغيل التجريبي، تُعرض قيم NULL على هيئة السلسلة الحرفية NULL من دون علامات اقتباس.

اكتشاف أعمدة الهوية

يحدد SqlGenerator الأعمدة المكوّنة لهوية الصف بالاستناد إلى TableSnapshot::identityColumns في لقطة الأساس. وتُستخدم هذه الأعمدة في بنود WHERE لعبارات UPDATE وDELETE، وتُستبعد من بنود SET في عبارات UPDATE.

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

تمرير برنامج تشغيل

للتحكم في طريقة اقتباس المعرّفات، مرّر مثيلًا من Driver:

PHP
use Merql\Driver\SqliteDriver;

$statements = SqlGenerator::generate(
    $result,
    driver: new SqliteDriver(),
);
// Uses double-quote quoting: "posts", "title"