Przejdź do treści

Generowanie SQL

SqlGenerator przekształca MergeResult w parametryzowane instrukcje SQL. Wszystkie wartości są przekazywane jako parametry, nigdy nie są wstawiane bezpośrednio do ciągu 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']
}

Użyj generateGuarded(), gdy sprawdzony plan scalania powinien zostać zastosowany tylko wtedy, gdy bieżące wiersze nadal odpowiadają oczekiwanemu zrzutowi.

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

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

Format instrukcji

Każda instrukcja to tablica asocjacyjna z dwoma kluczami:

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

Identyfikatory (nazwy tabel i kolumn) są cytowane zgodnie ze stylem sterownika bazy danych. MySQL używa znaków odwrotnego apostrofu, a SQLite używa podwójnych cudzysłowów. Jeśli nie podano sterownika, domyślnie używane są znaki odwrotnego apostrofu.

Kolejność operacji

Operacje są grupowane według typu i wykonywane w następującej kolejności:

  1. Najpierw INSERTs — nowe wiersze muszą istnieć, zanim odwołają się do nich aktualizacje.
  2. Następnie UPDATEs.
  3. Na końcu DELETEs — przed usunięciem trzeba usunąć odwołania do wierszy.
PHP
$statements = SqlGenerator::generate($result);
// All INSERTs, then all UPDATEs, then all DELETEs.

Kolejność kluczy obcych

Jeśli podano zależności kluczy obcych, operacje w każdej grupie są sortowane topologicznie. Tabele nadrzędne są przetwarzane przed podrzędnymi przy wstawianiu i aktualizowaniu. Przy usuwaniu tabele podrzędne są przetwarzane przed nadrzędnymi.

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 wykonuje sortowanie topologiczne grafu zależności. Wykrywa i przerywa zależności cykliczne, aby zapobiec nieskończonym pętlom.

Automatyczne wykrywanie kluczy obcych

Applier automatycznie odczytuje z bazy danych relacje kluczy obcych:

PHP
use Merql\Apply\Applier;

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

Przykłady wygenerowanych SQL

INSERT

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

Uwzględniane są wszystkie kolumny z wartości przekazanych w operacji.

UPDATE

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

Kolumny identyfikacyjne (klucz główny) są pomijane w klauzuli SET i używane w klauzuli WHERE. Wartości klauzuli WHERE pochodzą z dekodowania klucza wiersza.

DELETE

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

W klauzuli WHERE występują wyłącznie kolumny identyfikacyjne.

UPDATE z kontrolą

Aktualizacje z kontrolą zawierają zarówno klauzule dotyczące tożsamości, jak i klauzule dotyczące oczekiwanego bieżącego wiersza.

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

Jeśli wiersz nie ma już oczekiwanej status, instrukcja nie zmienia żadnych wierszy, a zabezpieczone zastosowanie wycofuje transakcję.

Zabezpieczony INSERT

Zabezpieczone wstawienia używają NOT EXISTS, aby uniknąć wstawienia do tożsamości, która pojawiła się po utworzeniu planu.

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

Obsługa NULL

Wartości NULL są przekazywane jako PHP null w tablicy params. Adapter połączenia obsługuje wiązanie parametrów:

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

W wynikach próbnego uruchomienia wartości NULL są wyświetlane jako literał NULL bez cudzysłowów.

Wykrywanie kolumny tożsamości

SqlGenerator ustala, które kolumny tworzą tożsamość wiersza, na podstawie TableSnapshot::identityColumns migawki bazowej. Kolumny te są używane w klauzulach WHERE instrukcji UPDATE i DELETE oraz pomijane w klauzulach SET instrukcji UPDATE.

Jeśli migawka bazowa jest niedostępna, jako rozwiązanie awaryjne używana jest pierwsza kolumna w tablicy values. Jeśli tablica values jest pusta, zakłada się id.

Przekazywanie sterownika

Aby kontrolować sposób cytowania identyfikatorów, przekaż instancję Driver:

PHP
use Merql\Driver\SqliteDriver;

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