Ga naar de inhoud

Genereren van SQL

SqlGenerator zet een MergeResult om in geparametriseerde SQL-instructies. Alle waarden worden als parameters gebonden en nooit in de SQL-string ingevuld.

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']
}

Gebruik generateGuarded() wanneer een beoordeeld samenvoegingsplan alleen mag worden toegepast als live rijen nog overeenkomen met een verwachte snapshot.

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

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

Instructieformaat

Elke instructie is een associatieve array met twee sleutels:

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

Identifiers (tabel- en kolomnamen) worden geciteerd volgens de stijl van de databasedriver. MySQL gebruikt backticks en SQLite gebruikt dubbele aanhalingstekens. Als er geen driver is opgegeven, worden standaard backticks gebruikt.

Volgorde van bewerkingen

Bewerkingen worden gegroepeerd op type en in deze volgorde uitgevoerd:

  1. Eerst INSERTs -- nieuwe rijen moeten bestaan voordat ernaar kan worden verwezen in updates.
  2. Daarna UPDATEs.
  3. Tot slot DELETEs -- verwijzingen naar rijen moeten worden verwijderd voordat die rijen worden verwijderd.
PHP
$statements = SqlGenerator::generate($result);
// All INSERTs, then all UPDATEs, then all DELETEs.

Volgorde op basis van foreign keys

Wanneer afhankelijkheden van foreign keys zijn opgegeven, worden bewerkingen binnen elke groep topologisch gesorteerd. Bovenliggende tabellen worden vóór onderliggende tabellen verwerkt bij inserts en updates. Bij deletes worden onderliggende tabellen vóór bovenliggende tabellen verwerkt.

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 voert een topologische sortering uit op de afhankelijkheidsgraaf. Circulaire afhankelijkheden worden gedetecteerd en doorbroken om oneindige lussen te voorkomen.

FK's automatisch detecteren

Applier leest automatisch relaties tussen foreign keys uit de database:

PHP
use Merql\Apply\Applier;

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

Voorbeelden van gegenereerde SQL

INSERT

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

Alle kolommen uit de waarden van de bewerking worden opgenomen.

UPDATE

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

Identiteitskolommen (primary key) worden uitgesloten van de SET-clausule en gebruikt in de WHERE-clausule. De waarden voor de WHERE-clausule worden verkregen door de rijsleutel te decoderen.

DELETE

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

Alleen identiteitskolommen staan in de WHERE-clausule.

Beveiligde UPDATE

Beveiligde updates bevatten zowel identiteitsclausules als clausules voor verwachte live rijen.

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

Als de rij niet langer de verwachte status heeft, beïnvloedt de instructie nul rijen en draait beveiligd toepassen de transactie terug.

Beveiligde INSERT

Beveiligde inserts gebruiken NOT EXISTS om te voorkomen dat er wordt ingevoegd voor een identiteit die is verschenen nadat het plan is gemaakt.

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

NULL verwerken

NULL-waarden worden als PHP null doorgegeven in de params-array. De verbindingsadapter verzorgt de binding:

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

In de uitvoer van een dry run worden NULL-waarden weergegeven als de letterlijke string NULL, zonder aanhalingstekens.

Identiteitskolommen detecteren

SqlGenerator bepaalt welke kolommen de rij-identiteit vormen door naar TableSnapshot::identityColumns van de basissnapshot te kijken. Deze kolommen worden gebruikt voor WHERE-clausules bij UPDATE- en DELETE-instructies en uitgesloten van SET-clausules bij UPDATE's.

Als er geen basissnapshot beschikbaar is, wordt de eerste kolom in de values-array als terugvaloptie gebruikt. Als de values-array leeg is, wordt id aangenomen.

Een driver doorgeven

Geef een instantie van Driver door om te bepalen hoe identifiers worden geciteerd:

PHP
use Merql\Driver\SqliteDriver;

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